diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs index e42aa0547..37f6c91ed 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs @@ -342,7 +342,7 @@ namespace Barotrauma partial void SetupDrawOrder() { - //make sure every character gets drawn at a distinct "layer" + //make sure every character gets drawn at a distinct "layer" //(instead of having some of the limbs appear behind and some in front of other characters) float startDepth = 0.1f; float increment = 0.001f; @@ -355,8 +355,16 @@ namespace Barotrauma List depthSortedLimbs = Limbs.OrderBy(l => l.DefaultSpriteDepth).ToList(); foreach (Limb limb in Limbs) { - if (limb.ActiveSprite == null) { continue; } - limb.ActiveSprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f; + var sprite = limb.GetActiveSprite(); + if (sprite == null) { continue; } + sprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f; + foreach (var conditionalSprite in limb.ConditionalSprites) + { + if (conditionalSprite.Exclusive) + { + conditionalSprite.ActiveSprite.Depth = sprite.Depth; + } + } } foreach (Limb limb in Limbs) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs index c5d75f86c..3ee39ef88 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs @@ -128,6 +128,50 @@ namespace Barotrauma get { return gibEmitters; } } + private class GUIMessage + { + public string RawText; + public string Identifier; + public string Text; + + private int _value; + public int Value + { + get { return _value; } + set + { + _value = value; + Text = RawText.Replace("[value]", _value.ToString()); + Size = GUI.Font.MeasureString(Text); + } + } + + public Color Color; + public float Lifetime; + public float Timer; + + public Vector2 Size; + + public bool PlaySound; + + public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null) + { + RawText = Text = rawText; + if (value.HasValue) + { + Text = rawText.Replace("[value]", value.Value.ToString()); + Value = value.Value; + } + Timer = -delay; + Size = GUI.Font.MeasureString(Text); + Color = color; + Identifier = identifier; + Lifetime = 3.0f; + } + } + + private List guiMessages = new List(); + public static bool IsMouseOnUI => GUI.MouseOn != null || (CharacterInventory.IsMouseOnInventory && !CharacterInventory.DraggingItemToWorld); @@ -618,6 +662,17 @@ namespace Barotrauma } } + foreach (GUIMessage message in guiMessages) + { + bool wasPending = message.Timer < 0.0f; + message.Timer += deltaTime; + if (wasPending && message.Timer >= 0.0f && message.PlaySound) + { + SoundPlayer.PlayUISound(GUISoundType.UIMessage); + } + } + guiMessages.RemoveAll(m => m.Timer >= m.Lifetime); + if (!enabled) { return; } if (!IsIncapacitated) @@ -736,6 +791,27 @@ namespace Barotrauma CharacterHUD.Draw(spriteBatch, this, cam); if (drawHealth && !CharacterHUD.IsCampaignInterfaceOpen) { CharacterHealth.DrawHUD(spriteBatch); } } + + public void DrawGUIMessages(SpriteBatch spriteBatch, Camera cam) + { + if (info == null || !Enabled || InvisibleTimer > 0.0f) + { + return; + } + + Vector2 messagePos = DrawPosition; + messagePos.Y += hudInfoHeight; + messagePos = cam.WorldToScreen(messagePos) - Vector2.UnitY * GUI.IntScale(60); + foreach (GUIMessage message in guiMessages) + { + if (message.Timer < 0) { continue; } + Vector2 drawPos = messagePos + Vector2.UnitX * (GUI.IntScale(60) - message.Size.X); + drawPos = new Vector2((int)drawPos.X, (int)drawPos.Y); + float alpha = MathHelper.SmoothStep(1.0f, 0.0f, message.Timer / message.Lifetime); + GUI.DrawString(spriteBatch, drawPos, message.Text, message.Color * alpha); + messagePos -= Vector2.UnitY * message.Size.Y * 1.2f; + } + } public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam) { @@ -942,6 +1018,55 @@ namespace Barotrauma return nameColor; } + public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null) + { + GUIMessage existingMessage = null; + + float delay = 0.0f; + if (guiMessages.Any()) + { + delay = guiMessages.Min(m => m.Timer) - 0.5f; + if (delay < 0) + { + delay = -delay; + if (guiMessages.Count > 5) + { + //reduce delays if there's lots of messages + guiMessages.Where(m => m.Timer < 0.0f).ForEach(m => m.Timer *= 0.9f); + } + } + else + { + delay = 0; + } + } + + if (identifier != null) + { + existingMessage = guiMessages.Find(m => m.Identifier == identifier && m.Timer < m.Lifetime * 0.5f); + } + if (existingMessage == null || !value.HasValue) + { + var newMessage = new GUIMessage(rawText, color, delay, identifier, value); + guiMessages.Insert(0, newMessage); + if (playSound) + { + if (delay > 0.0f) + { + newMessage.PlaySound = true; + } + else + { + SoundPlayer.PlayUISound(GUISoundType.UIMessage); + } + } + } + else + { + existingMessage.Value += value.Value; + } + } + /// /// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object) /// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time @@ -1046,24 +1171,14 @@ namespace Barotrauma if (newAmount > prevAmount) { int increase = newAmount - prevAmount; - GUI.AddMessage( - "+" + TextManager.GetWithVariable("currencyformat", "[credits]", increase.ToString()), - GUI.Style.Yellow, - Position + Vector2.UnitY * 150.0f, - Vector2.UnitY * 10.0f, - playSound: true, - subId: Submarine?.ID ?? -1); + AddMessage("+" + TextManager.GetWithVariable("currencyformat", "[credits]", "[value]"), + GUI.Style.Yellow, playSound: this == Controlled, "money", increase); } } partial void OnTalentGiven(string talentIdentifier) { - GUI.AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()), - GUI.Style.Yellow, - Position + Vector2.UnitY * 150.0f, - Vector2.UnitY * 10.0f, - playSound: true, - subId: Submarine?.ID ?? -1); + AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()), GUI.Style.Yellow, playSound: this == Controlled); } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs index b85a2b0e2..d8b6cda3a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs @@ -187,7 +187,7 @@ namespace Barotrauma return frame; } - partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos) + partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel) { if (TeamID == CharacterTeamType.FriendlyNPC) { return; } if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; } @@ -198,17 +198,14 @@ namespace Barotrauma if ((int)newLevel > (int)prevLevel) { int increase = Math.Max((int)newLevel - (int)prevLevel, 1); - GUI.AddMessage( - string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)), - specialIncrease ? GUI.Style.Orange : GUI.Style.Green, - textPopupPos, - Vector2.UnitY * 10.0f, - playSound: specialIncrease, - subId: Character?.Submarine?.ID ?? -1); + Character?.AddMessage( + "+[value] "+ TextManager.Get("SkillName." + skillIdentifier), + specialIncrease ? GUI.Style.Orange : GUI.Style.Green, + playSound: Character == Character.Controlled, skillIdentifier, increase); } } - partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos) + partial void OnExperienceChanged(int prevAmount, int newAmount) { if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; } @@ -217,13 +214,9 @@ namespace Barotrauma if (newAmount > prevAmount) { int increase = newAmount - prevAmount; - GUI.AddMessage( - string.Format("+{0} {1}", increase, TextManager.Get("experienceshort")), - GUI.Style.Blue, - textPopupPos, - Vector2.UnitY * 10.0f, - playSound: true, - subId: Character?.Submarine?.ID ?? -1); + Character?.AddMessage( + "+[value] " + TextManager.Get("experienceshort"), + GUI.Style.Blue, playSound: Character == Character.Controlled, "exp", increase); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index 34a5e6378..925021818 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -358,7 +358,7 @@ namespace Barotrauma { string skillIdentifier = msg.ReadString(); float skillLevel = msg.ReadSingle(); - info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f); + info?.SetSkillLevel(skillIdentifier, skillLevel); } break; case 4: // NetEntityEvent.Type.SetAttackTarget @@ -390,7 +390,7 @@ namespace Barotrauma } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; } - if (attackLimb?.attack != null) + if (attackLimb?.attack != null && Controlled != this) { if (eventType == 4) { @@ -467,8 +467,9 @@ namespace Barotrauma ushort talentCount = msg.ReadUInt16(); for (int i = 0; i < talentCount; i++) { + bool addedThisRound = msg.ReadBoolean(); UInt32 talentIdentifier = msg.ReadUInt32(); - GiveTalent(talentIdentifier); + GiveTalent(talentIdentifier, addedThisRound); } break; case 12: //NetEntityEvent.Type.UpdateMoney: diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs index 945f8acc3..9ee0fa4ba 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs @@ -1969,8 +1969,8 @@ namespace Barotrauma if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue; foreach (Affliction a in limbHealths[limb.HealthIndex].Afflictions) { - limb.BurnOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.BurnOverlayAlpha; - limb.DamageOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.DamageOverlayAlpha; + limb.BurnOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.BurnOverlayAlpha; + limb.DamageOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.DamageOverlayAlpha; } limb.BurnOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count; limb.DamageOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs index 88b7bc21d..42ba80997 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs @@ -167,6 +167,10 @@ namespace Barotrauma } } + public Sprite GetActiveSprite(bool excludeConditionalSprites = true) + => excludeConditionalSprites ? (_deformSprite != null ? _deformSprite.Sprite : Sprite) + : ActiveSprite; + public float DefaultSpriteDepth { get; private set; } public WearableSprite HuskSprite { get; private set; } @@ -397,7 +401,7 @@ namespace Barotrauma return deformations; } } - DefaultSpriteDepth = ActiveSprite.Depth; + DefaultSpriteDepth = GetActiveSprite()?.Depth ?? 0.0f; LightSource?.CheckConditionals(); } @@ -901,7 +905,7 @@ namespace Barotrauma } foreach (WearableSprite wearable in WearingItems) { - if (onlyDrawable != null && onlyDrawable != wearable) continue; + if (onlyDrawable != null && onlyDrawable != wearable && wearable.CanBeHiddenByOtherWearables) { continue; } DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect); //if there are multiple sprites on this limb, make the successive ones be drawn in front depthStep += step; diff --git a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs index 90c057cab..68aa6da0c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs @@ -695,7 +695,12 @@ namespace Barotrauma AssignOnExecute("control", (string[] args) => { - if (args.Length < 1) return; + if (args.Length < 1) { return; } + if (GameMain.NetworkMember != null) + { + GameMain.Client?.SendConsoleCommand("control " + string.Join(' ', args[0])); + return; + } var character = FindMatchingCharacter(args, true); if (character != null) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs index e7a0a3af5..18c65a9f7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs @@ -941,7 +941,7 @@ namespace Barotrauma inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame); } - if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || prevMouseOn == null) + if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || (prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld())) { for (var i = updateList.Count - 1; i > inventoryIndex; i--) { @@ -2454,7 +2454,7 @@ namespace Barotrauma { Submarine sub = Submarine.Loaded.FirstOrDefault(s => s.ID == subId); - var newMessage = new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, LargeFont, sub: sub); + var newMessage = new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, Font, sub: sub); if (playSound) { SoundPlayer.PlayUISound(soundType); } bool overlapFound = true; int tries = 0; @@ -2477,8 +2477,7 @@ namespace Barotrauma moveDir = Rand.Vector(1.0f); } moveDir.Y = -Math.Abs(moveDir.Y); - newMessage.Pos += moveDir * 20; - overlapFound = true; + newMessage.Pos -= Vector2.UnitY * 10; } tries++; if (tries > 20) { break; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs index 086cc25e7..e7be6a3ec 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs @@ -174,7 +174,7 @@ namespace Barotrauma if (BlendState != null) { spriteBatch.End(); - spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState); + spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); } if (style != null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs index f3957f392..2a010e707 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs @@ -1026,7 +1026,6 @@ namespace Barotrauma ContentBackground.DrawManually(spriteBatch, alsoChildren: false); Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle; - RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState; if (HideChildrenOutsideFrame) { spriteBatch.End(); @@ -1054,7 +1053,7 @@ namespace Barotrauma { spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect; - spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState); + spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); } if (ScrollBarVisible) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs index 923728eaa..6c6224e8f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs @@ -511,5 +511,22 @@ namespace Barotrauma targetComponent.ApplyStyle(componentStyle); } + + public Color GetQualityColor(int quality) + { + switch (quality) + { + case 1: + return ItemQualityColorGood; + case 2: + return ItemQualityColorExcellent; + case 3: + return ItemQualityColorMasterwork; + case -1: + return ItemQualityColorPoor; + default: + return ItemQualityColorNormal; + } + } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs index 5e5a9357a..cb663cdcf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs @@ -444,9 +444,9 @@ namespace Barotrauma.Items.Components public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { } - public virtual void AddToGUIUpdateList() + public virtual void AddToGUIUpdateList(int order = 0) { - GuiFrame?.AddToGUIUpdateList(); + GuiFrame?.AddToGUIUpdateList(order: order); } public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs index ff08aa3e2..d94357008 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs @@ -410,13 +410,13 @@ namespace Barotrauma.Items.Components return true; } - public override void AddToGUIUpdateList() + public override void AddToGUIUpdateList(int order = 0) { - base.AddToGUIUpdateList(); - hullInfoFrame.AddToGUIUpdateList(order: 1); + base.AddToGUIUpdateList(order); + hullInfoFrame.AddToGUIUpdateList(order: order + 1); if (currentMode == MiniMapMode.ItemFinder && searchBar.Selected) { - searchAutoComplete.AddToGUIUpdateList(order: 1); + searchAutoComplete.AddToGUIUpdateList(order: order + 1); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/RemoteController.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/RemoteController.cs index bf5405474..6f6d3d740 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/RemoteController.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/RemoteController.cs @@ -14,9 +14,9 @@ namespace Barotrauma.Items.Components currentTarget?.UpdateHUD(cam, character,deltaTime); } - public override void AddToGUIUpdateList() + public override void AddToGUIUpdateList(int order = 0) { - currentTarget?.AddToGUIUpdateList(); + currentTarget?.AddToGUIUpdateList(order: -1); } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs index 1162e4bff..72e8482da 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs @@ -88,11 +88,6 @@ namespace Barotrauma.Items.Components return character == Character.Controlled && character == user && character.SelectedConstruction == item; } - public override void AddToGUIUpdateList() - { - GuiFrame?.AddToGUIUpdateList(); - } - public override void UpdateHUD(Character character, float deltaTime, Camera cam) { if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs index e13440e0e..a816f402a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs @@ -118,9 +118,9 @@ namespace Barotrauma.Items.Components // This method is overrided instead of the UpdateHUD method because this ensures the input box is selected // even when the terminal component is selected for the very first time. Doing the input box selection in the // UpdateHUD method only selects the input box on every terminal selection except for the very first time. - public override void AddToGUIUpdateList() + public override void AddToGUIUpdateList(int order = 0) { - base.AddToGUIUpdateList(); + base.AddToGUIUpdateList(order: order); if (shouldSelectInputBox) { inputBox.Select(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Wearable.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Wearable.cs index b489954a0..10d0fc376 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Wearable.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Wearable.cs @@ -5,9 +5,9 @@ namespace Barotrauma.Items.Components { partial class Wearable { - private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier) + private void GetDamageModifierText(ref string description, DamageModifier damageModifier, string afflictionIdentifier) { - int roundedValue = (int)Math.Round((1 - damageMultiplier) * 100); + int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100); if (roundedValue == 0) { return; } string colorStr = XMLExtensions.ColorToString(GUI.Style.Green); description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}"; @@ -15,7 +15,7 @@ namespace Barotrauma.Items.Components public override void AddTooltipInfo(ref string name, ref string description) { - if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any()) + if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f) || !MathUtils.NearlyEqual(d.ProbabilityMultiplier, 1f)) || SkillModifiers.Any()) { description += "\n"; } @@ -31,11 +31,11 @@ namespace Barotrauma.Items.Components foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers) { - GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier); + GetDamageModifierText(ref description, damageModifier, afflictionIdentifier); } foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes) { - GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier); + GetDamageModifierText(ref description, damageModifier, afflictionIdentifier); } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index 045117832..a8d965902 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -601,7 +601,10 @@ namespace Barotrauma { var slotRef = new SlotReference(this, slot, slotIndex, isSubSlot, slots[slotIndex].FirstOrDefault()?.GetComponent()?.Inventory); if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && slotRef.ParentInventory is CharacterInventory) { return; } - selectedSlot = slotRef; + if (CanSelectSlot(slotRef)) + { + selectedSlot = slotRef; + } } if (!DraggingItems.Any()) @@ -1302,39 +1305,46 @@ namespace Barotrauma DraggingItems.Clear(); } - if (selectedSlot != null) + if (selectedSlot != null && !CanSelectSlot(selectedSlot)) { - if (!selectedSlot.Slot.MouseOn()) + selectedSlot = null; + } + } + + private static bool CanSelectSlot(SlotReference selectedSlot) + { + if (!selectedSlot.Slot.MouseOn()) + { + return false; + } + else + { + var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner(); + if (selectedSlot.ParentInventory?.Owner != Character.Controlled && + selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter && + selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction && + !(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) && + rootOwner != Character.Controlled && + rootOwner != Character.Controlled.SelectedCharacter && + rootOwner != Character.Controlled.SelectedConstruction && + !(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false)) { - selectedSlot = null; + return false; } - else + var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item; + if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) && + ownerCharacter == Character.Controlled && + CharacterHealth.OpenHealthWindow?.Character != ownerCharacter && + ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface)) { - var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner(); - if (selectedSlot.ParentInventory?.Owner != Character.Controlled && - selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter && - selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction && - !(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) && - rootOwner != Character.Controlled && - rootOwner != Character.Controlled.SelectedCharacter && - rootOwner != Character.Controlled.SelectedConstruction && - !(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false)) - { - selectedSlot = null; - } - var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item; - if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) && - ownerCharacter == Character.Controlled && - CharacterHealth.OpenHealthWindow?.Character != ownerCharacter && - ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface)) - { - highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem); - selectedSlot = null; - } + highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem); + return false; } } + return true; } + protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot) { Rectangle hoverArea; @@ -1548,7 +1558,7 @@ namespace Barotrauma var indicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator.Default"); Sprite indicatorSprite = indicatorStyle?.GetDefaultSprite(); Sprite emptyIndicatorSprite = indicatorStyle?.GetSprite(GUIComponent.ComponentState.Hover); - DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition); + DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition); } if (itemContainer != null && itemContainer.ShowContainedStateIndicator) @@ -1591,6 +1601,19 @@ namespace Barotrauma DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, containedIndicatorArea, containedState, pulsate: !usingDefaultSprite && containedState >= 0.0f && containedState < 0.25f && inventory == Character.Controlled?.Inventory && Character.Controlled.HasEquippedItem(item)); } + + if (item.Quality != 0) + { + var style = GUI.Style.GetComponentStyle("InnerGlowSmall"); + if (style == null) + { + GUI.DrawRectangle(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.7f); + } + else + { + style.Sprites[GUIComponent.ComponentState.None].FirstOrDefault()?.Draw(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.5f); + } + } } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs index 8e50e4018..900731c83 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs @@ -1199,7 +1199,7 @@ namespace Barotrauma return texts; } - public override void AddToGUIUpdateList() + public override void AddToGUIUpdateList(int order = 0) { if (Screen.Selected is SubEditorScreen) { @@ -1231,7 +1231,7 @@ namespace Barotrauma bool wasUsingAlternativeLayout = ic.UseAlternativeLayout; ic.UseAlternativeLayout = useAlternativeLayout; needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout; - ic.AddToGUIUpdateList(); + ic.AddToGUIUpdateList(order); } if (itemInUseWarning != null && itemInUseWarning.Visible) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs index 3664afb1d..642813f4f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs @@ -1021,9 +1021,9 @@ namespace Barotrauma return newEntities; } - public virtual void AddToGUIUpdateList() + public virtual void AddToGUIUpdateList(int order = 0) { - if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList(); + if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(order: order); } } public virtual void UpdateEditing(Camera cam, float deltaTime) { } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index e46694429..0a553e0a8 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -497,7 +497,6 @@ namespace Barotrauma.CharacterEditor } if (PlayerInput.KeyHit(InputType.Run)) { - // TODO: refactor this horrible hacky index manipulation mess int index = 0; bool isSwimming = character.AnimController.ForceSelectAnimationType == AnimationType.SwimFast || character.AnimController.ForceSelectAnimationType == AnimationType.SwimSlow; bool isMovingFast = character.AnimController.ForceSelectAnimationType == AnimationType.Run || character.AnimController.ForceSelectAnimationType == AnimationType.SwimFast; @@ -505,23 +504,25 @@ namespace Barotrauma.CharacterEditor { if (isSwimming || !character.AnimController.CanWalk) { - index = !character.AnimController.CanWalk ? 0 : (int)AnimationType.SwimSlow - 1; + index = !character.AnimController.CanWalk ? (int)AnimationType.SwimFast : (int)AnimationType.SwimSlow; } else { - index = (int)AnimationType.Walk - 1; + index = (int)AnimationType.Walk; } + index -= 1; } else { if (isSwimming || !character.AnimController.CanWalk) { - index = !character.AnimController.CanWalk ? 1 : (int)AnimationType.SwimFast - 1; + index = !character.AnimController.CanWalk ? (int)AnimationType.SwimSlow : (int)AnimationType.SwimFast; } else { - index = (int)AnimationType.Run - 1; + index = (int)AnimationType.Run; } + index -= 1; } if (animSelection.SelectedIndex != index) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs index da8e8bf52..9a0675524 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs @@ -92,8 +92,7 @@ namespace Barotrauma } } - if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList(); - + GameMain.GameSession?.AddToGUIUpdateList(); Character.AddAllToGUIUpdateList(); } @@ -139,7 +138,7 @@ namespace Barotrauma for (int i = 0; i < Submarine.MainSubs.Length; i++) { if (Submarine.MainSubs[i] == null) continue; - if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) continue; + if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) { continue; } Vector2 position = Submarine.MainSubs[i].SubBody != null ? Submarine.MainSubs[i].WorldPosition : Submarine.MainSubs[i].HiddenSubPosition; @@ -151,6 +150,14 @@ namespace Barotrauma } } + if (!GUI.DisableHUD) + { + foreach (Character c in Character.CharacterList) + { + c.DrawGUIMessages(spriteBatch, cam); + } + } + GUI.Draw(cam, spriteBatch); spriteBatch.End(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index 093e093db..40b99af75 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -1737,9 +1737,10 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.GetWithVariable("startingequipmentname", "[number]", (variant + 1).ToString()), font: GUI.SubHeadingFont, textAlignment: Alignment.Center); - var itemIdentifiers = jobPrefab.ItemIdentifiers[variant] - .Distinct() - .Where(id => jobPrefab.ShowItemPreview[variant][id]); + var itemIdentifiers = jobPrefab.PreviewItems[variant] + .Where(it => it.ShowPreview) + .Select(it => it.ItemIdentifier) + .Distinct(); int itemsPerRow = 5; int rows = (int)Math.Max(Math.Ceiling(itemIdentifiers.Count() / (float)itemsPerRow), 1); @@ -2624,9 +2625,10 @@ namespace Barotrauma private void DrawJobVariantItems(SpriteBatch spriteBatch, GUICustomComponent component, Pair jobPrefab, int itemsPerRow) { - var itemIdentifiers = jobPrefab.First.ItemIdentifiers[jobPrefab.Second] - .Distinct() - .Where(id => jobPrefab.First.ShowItemPreview[jobPrefab.Second][id]); + var itemIdentifiers = jobPrefab.First.PreviewItems[jobPrefab.Second] + .Where(it => it.ShowPreview) + .Select(it => it.ItemIdentifier) + .Distinct(); Point slotSize = new Point(component.Rect.Height); int spacing = (int)(5 * GUI.Scale); @@ -2645,7 +2647,7 @@ namespace Barotrauma int i = 0; Rectangle tooltipRect = Rectangle.Empty; string tooltip = null; - foreach (string itemIdentifier in itemIdentifiers) + foreach (var itemIdentifier in itemIdentifiers) { if (!(MapEntityPrefab.Find(null, identifier: itemIdentifier, showErrorMessages: false) is ItemPrefab itemPrefab)) { continue; } @@ -2664,7 +2666,7 @@ namespace Barotrauma float iconScale = Math.Min(Math.Min(slotSize.X / icon.size.X, slotSize.Y / icon.size.Y), 2.0f) * 0.9f; icon.Draw(spriteBatch, slotPos + slotSize.ToVector2() * 0.5f, scale: iconScale); - int count = jobPrefab.First.ItemIdentifiers[jobPrefab.Second].Count(id => id == itemIdentifier); + int count = jobPrefab.First.PreviewItems[jobPrefab.Second].Count(it => it.ShowPreview && it.ItemIdentifier == itemIdentifier); if (count > 1) { string itemCountText = "x" + count; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs index 5a9c265f1..ed81e93a2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs @@ -169,7 +169,7 @@ namespace Barotrauma } else { - DebugConsole.ThrowError("Sprite \"" + file + "\" not found!"); + DebugConsole.ThrowError($"Sprite \"{file}\" not found! {Environment.StackTrace.CleanupStackTrace()}"); } return null; diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 74dd10f01..0b19d09f4 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index aec74e517..9859d339c 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 45c89c098..5a7a69f25 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 71e623332..9b9857398 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index bc313d665..99db95ee4 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs index 04fa5c705..44df073ae 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs @@ -10,7 +10,7 @@ namespace Barotrauma { private readonly Dictionary prevSentSkill = new Dictionary(); - partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos) + partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel) { if (Character == null || Character.Removed) { return; } if (!prevSentSkill.ContainsKey(skillIdentifier)) @@ -24,9 +24,9 @@ namespace Barotrauma } } - partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos) + partial void OnExperienceChanged(int prevAmount, int newAmount) { - if (Math.Abs(prevAmount - newAmount) > 0) + if (prevAmount != newAmount) { GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience }); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index f5c86cae2..65861aecc 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -430,6 +430,7 @@ namespace Barotrauma msg.Write((ushort)characterTalents.Count); foreach (var unlockedTalent in characterTalents) { + msg.Write(unlockedTalent.AddedThisRound); msg.Write(unlockedTalent.Prefab.UIntIdentifier); } break; diff --git a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs index 796c72d08..cc969a0dd 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs @@ -1731,7 +1731,9 @@ namespace Barotrauma "givetalent", (Client client, Vector2 cursorWorldPos, string[] args) => { - Character targetCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false); + if (args.Length == 0) { return; } + Character targetCharacter = (args.Length >= 2) ? FindMatchingCharacter(args.Skip(1).ToArray(), false) : client.Character; + if (targetCharacter == null) { return; } TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c => @@ -1845,7 +1847,7 @@ namespace Barotrauma "control", (Client client, Vector2 cursorWorldPos, string[] args) => { - if (args.Length < 1) return; + if (args.Length < 1) { return; } var character = FindMatchingCharacter(args, ignoreRemotePlayers: true, allowedRemotePlayer: client); if (character != null) { @@ -2259,13 +2261,13 @@ namespace Barotrauma { foreach (Skill skill in character.Info.Job.Skills) { - character.Info.SetSkillLevel(skill.Identifier, level, character.WorldPosition); + character.Info.SetSkillLevel(skill.Identifier, level); } GameMain.Server.SendConsoleMessage($"Set all {character.Name}'s skills to {level}", senderClient); } else { - character.Info.SetSkillLevel(skillIdentifier, level, character.WorldPosition); + character.Info.SetSkillLevel(skillIdentifier, level); GameMain.Server.SendConsoleMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", senderClient); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 81e8e11ca..2486286e3 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -1181,6 +1181,10 @@ namespace Barotrauma.Networking { c.Character.ServerRead(objHeader, inc, c); } + else + { + DebugConsole.AddWarning($"Received character inputs from a client who's not controlling a character ({c.Name})."); + } break; case ClientNetObject.ENTITY_STATE: entityEventManager.Read(inc, c); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 4dc1f8bf0..b5edb232b 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.6.0 + 0.1500.7.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs index d6e3520d9..c5e455940 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs @@ -103,6 +103,9 @@ namespace Barotrauma !pathSteering.CurrentPath.Unreachable && (!requireNonDirty || !pathSteering.IsPathDirty); + public bool IsCurrentPathUnreachable => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Unreachable; + public bool IsCurrentPathFinished => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Finished; + protected readonly float colliderWidth; protected readonly float minGapSize; protected readonly float colliderLength; @@ -412,7 +415,7 @@ namespace Barotrauma } else if (EscapeTarget != null && EscapeTarget.FlowTargetHull != Character.CurrentHull) { - if (pathSteering.CurrentPath != null && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable) + if (IsCurrentPathUnreachable) { unreachableGaps.Add(EscapeTarget); EscapeTarget = null; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index c1a35d954..332c4d3fe 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -453,7 +453,7 @@ namespace Barotrauma if (SelectedAiTarget?.Entity != null || EscapeTarget != null) { Entity t = SelectedAiTarget?.Entity ?? EscapeTarget; - float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X; + float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(requireNonDirty: true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X; Character.AnimController.TargetDir = Character.WorldPosition.X < referencePos ? Direction.Right : Direction.Left; } else @@ -916,9 +916,7 @@ namespace Barotrauma { if (SteeringManager is IndoorsSteeringManager pathSteering) { - if (patrolTarget == null || - pathSteering.CurrentPath == null || - !pathSteering.IsPathDirty && (pathSteering.CurrentPath.Finished || pathSteering.CurrentPath.Unreachable)) + if (patrolTarget == null || IsCurrentPathUnreachable || IsCurrentPathFinished) { newPatrolTargetTimer = Math.Min(newPatrolTargetTimer, newPatrolTargetIntervalMin); } @@ -936,8 +934,7 @@ namespace Barotrauma else if (targetHulls.Any()) { patrolTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced); - var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n)); - + var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, Character.Submarine, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n)); if (path.Unreachable) { //can't go to this room, remove it from the list and try another room @@ -2331,34 +2328,32 @@ namespace Barotrauma SelectedAiTarget.Entity is Character c && VisibleHulls.Contains(c.CurrentHull)) { // Steer towards the target if in the same room and swimming - Vector2 dir = Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition); - if (MathUtils.IsValid(dir)) - { - SteeringManager.SteeringManual(deltaTime, dir); - } + SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition)); } else { // Use path finding PathSteering.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), weight: 2, minGapWidth: minGapSize); - if (!PathSteering.IsPathDirty && PathSteering.CurrentPath.Unreachable) - { - // Can't reach - State = AIState.Idle; - IgnoreTarget(SelectedAiTarget); - return; - } } } else { // Outside SteeringManager.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), 5); - if (Character.AnimController.InWater) + } + if (steeringManager is IndoorsSteeringManager pathSteering) + { + if (!pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable) { - SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15); + // Can't reach + State = AIState.Idle; + IgnoreTarget(SelectedAiTarget); } } + else if (Character.AnimController.InWater) + { + SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15); + } } #region Targeting @@ -2510,6 +2505,11 @@ namespace Barotrauma else if (targetingFromOutsideToInside) { targetingTag = "room"; + if (item.Submarine?.Info.IsRuin != null) + { + // Ignore ruin items when the creature is outside. + continue; + } } } else if (targetingTag == "nasonov") diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs index eebf7b0ec..24491ff3d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs @@ -115,6 +115,11 @@ namespace Barotrauma IsPathDirty = true; } + public void SteeringSeekSimple(Vector2 targetSimPos, float weight = 1) + { + steering += base.DoSteeringSeek(targetSimPos, weight); + } + public void SteeringSeek(Vector2 target, float weight, float minGapWidth = 0, Func startNodeFilter = null, Func endNodeFilter = null, Func nodeFilter = null, bool checkVisiblity = true) { steering += CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity); @@ -164,7 +169,7 @@ namespace Barotrauma private Vector2 CalculateSteeringSeek(Vector2 target, float weight, float minGapSize = 0, Func startNodeFilter = null, Func endNodeFilter = null, Func nodeFilter = null, bool checkVisibility = true) { - bool needsNewPath = currentPath == null || currentPath.Unreachable; + bool needsNewPath = currentPath == null || currentPath.Unreachable || currentPath.Finished; if (!needsNewPath && character.Submarine != null && character.Params.PathFinderPriority > 0.5f) { Vector2 targetDiff = target - currentTarget; @@ -194,16 +199,8 @@ namespace Barotrauma SkipCurrentPathNodes(); currentTarget = target; Vector2 currentPos = host.SimPosition; - if (character != null && character.Submarine == null) - { - var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false); - if (targetHull != null && targetHull.Submarine != null) - { - currentPos -= targetHull.Submarine.SimPosition; - } - } - pathFinder.InsideSubmarine = character.Submarine != null; - pathFinder.ApplyPenaltyToOutsideNodes = character.PressureProtection <= 0; + pathFinder.InsideSubmarine = character.Submarine != null && !character.Submarine.Info.IsRuin; + 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) @@ -218,7 +215,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 && character.Submarine != null) + if (!useNewPath) { // 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. @@ -322,15 +319,26 @@ namespace Barotrauma doorsChecked = true; } Vector2 pos = host.SimPosition; - if (character != null && CurrentPath.CurrentNode?.Submarine != null) + if (character != null && CurrentPath.CurrentNode != null) { - if (character.Submarine == null) + var nodeSub = CurrentPath.CurrentNode.Submarine; + if (nodeSub != null) { - pos -= CurrentPath.CurrentNode.Submarine.SimPosition; + if (character.Submarine == null) + { + // Going inside + pos -= ConvertUnits.ToSimUnits(nodeSub.Position); + } + else if (character.Submarine != nodeSub) + { + // Different subs + pos -= ConvertUnits.ToSimUnits(nodeSub.Position - character.Submarine.Position); + } } - else if (character.Submarine != currentPath.CurrentNode.Submarine) + else if (character.Submarine != null) { - pos -= ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position); + // Going outside + pos += ConvertUnits.ToSimUnits(character.Submarine.Position); } } bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs index 1f5d54c45..6bdddd863 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs @@ -724,7 +724,10 @@ namespace Barotrauma } if (retreatTarget != null && character.CurrentHull != retreatTarget) { - TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true), + TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true) + { + UsePathingOutside = false + }, onAbandon: () => { if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull)) @@ -783,6 +786,7 @@ namespace Barotrauma TryAddSubObjective(ref followTargetObjective, constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true, closeEnough: 50) { + UsePathingOutside = false, IgnoreIfTargetDead = true, DialogueIdentifier = "dialogcannotreachtarget", TargetName = Enemy.DisplayName, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs index dc172e587..fe528d9dc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs @@ -334,7 +334,7 @@ namespace Barotrauma continue; } // Don't allow to go outside if not already outside. - var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, nodeFilter: node => node.Waypoint.CurrentHull != null); + var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, character.Submarine, nodeFilter: node => node.Waypoint.CurrentHull != null); if (path.Unreachable) { HumanAIController.UnreachableHulls.Add(hull); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs index 870b10333..dd98bf747 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -323,7 +323,7 @@ namespace Barotrauma // This is relatively expensive, so let's do this only when it significantly improves the behavior. // Only allow one path find call per frame. hasCalledPathFinder = true; - var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null); + var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, character.Submarine, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null); if (path.Unreachable) { continue; } } currItemPriority = itemPriority; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index ded911eea..f4e156d20 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -27,6 +27,7 @@ namespace Barotrauma public bool followControlledCharacter; public bool mimic; public bool SpeakIfFails { get; set; } = true; + public bool UsePathingOutside { get; set; } = true; public float extraDistanceWhileSwimming; public float extraDistanceOutsideSub; @@ -121,13 +122,14 @@ namespace Barotrauma } private readonly float avoidLookAheadDistance = 5; + private readonly float pathWaitingTime = 3; public AIObjectiveGoTo(ISpatialEntity target, Character character, AIObjectiveManager objectiveManager, bool repeat = false, bool getDivingGearIfNeeded = true, float priorityModifier = 1, float closeEnough = 0) : base(character, objectiveManager, priorityModifier) { Target = target; this.repeat = repeat; - waitUntilPathUnreachable = 3.0f; + waitUntilPathUnreachable = pathWaitingTime; this.getDivingGearIfNeeded = getDivingGearIfNeeded; if (Target is Item i) { @@ -186,7 +188,6 @@ namespace Barotrauma // Wait character.AIController.SteeringManager.Reset(); } - waitUntilPathUnreachable -= deltaTime; if (!character.IsClimbing) { character.SelectedConstruction = null; @@ -222,11 +223,13 @@ namespace Barotrauma { Abandon = true; } - else if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty) + else if (HumanAIController.IsCurrentPathUnreachable) { + waitUntilPathUnreachable -= deltaTime; SteeringManager.Reset(); if (waitUntilPathUnreachable < 0) { + waitUntilPathUnreachable = pathWaitingTime; if (repeat) { SpeakCannotReach(); @@ -325,25 +328,29 @@ namespace Barotrauma } else { - SeekGaps(maxGapDistance); - seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f); - if (TargetGap != null) + bool isRuins = character.Submarine?.Info.IsRuin != null || Target.Submarine?.Info.IsRuin != null; + if (!isRuins || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: true)) { - // Check that nothing is blocking the way - Vector2 rayStart = character.SimPosition; - Vector2 rayEnd = TargetGap.SimPosition; - if (TargetGap.Submarine != null && character.Submarine == null) + SeekGaps(maxGapDistance); + seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f); + if (TargetGap != null) { - rayStart -= TargetGap.Submarine.SimPosition; - } - else if (TargetGap.Submarine == null && character.Submarine != null) - { - rayEnd -= character.Submarine.SimPosition; - } - var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true); - if (closestBody != null) - { - TargetGap = null; + // Check that nothing is blocking the way + Vector2 rayStart = character.SimPosition; + Vector2 rayEnd = TargetGap.SimPosition; + if (TargetGap.Submarine != null && character.Submarine == null) + { + rayStart -= TargetGap.Submarine.SimPosition; + } + else if (TargetGap.Submarine == null && character.Submarine != null) + { + rayEnd -= character.Submarine.SimPosition; + } + var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true); + if (closestBody != null) + { + TargetGap = null; + } } } } @@ -454,19 +461,25 @@ namespace Barotrauma } else if (!isInside && HumanAIController.UseIndoorSteeringOutside) { - if (character.Submarine == null && Target.Submarine != null) - { - targetPos += Target.Submarine.SimPosition; - } - nodeFilter = n => n.Waypoint.Tunnel != null; + nodeFilter = n => n.Waypoint.Submarine == null; } - PathSteering.SteeringSeek(targetPos, weight: 1, - startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null), - endNodeFilter: endNodeFilter, - nodeFilter: nodeFilter, - checkVisiblity: CheckVisibility); - + if (!isInside && !UsePathingOutside) + { + PathSteering.SteeringSeekSimple(character.GetRelativeSimPosition(Target), 10); + if (character.AnimController.InWater) + { + SteeringManager.SteeringAvoid(deltaTime, avoidLookAheadDistance, weight: 15); + } + } + else + { + PathSteering.SteeringSeek(targetPos, weight: 1, + startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null), + endNodeFilter: endNodeFilter, + nodeFilter: nodeFilter, + checkVisiblity: CheckVisibility); + } if (!isInside && (PathSteering.CurrentPath == null || PathSteering.IsPathDirty || PathSteering.CurrentPath.Unreachable)) { if (useScooter) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs index 3be3dab7e..8d496ac2c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -251,7 +251,7 @@ namespace Barotrauma currentTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced); bool isInWrongSub = (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsEscorted) && character.Submarine.TeamID != character.TeamID; bool isCurrentHullAllowed = !isInWrongSub && !IsForbidden(character.CurrentHull); - var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: null, nodeFilter: node => + var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, character.Submarine, nodeFilter: node => { if (node.Waypoint.CurrentHull == null) { return false; } // Check that there is no unsafe hulls on the way to the target diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs index 86756d255..be18f3e28 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs @@ -1,7 +1,6 @@ using Barotrauma.Extensions; using Microsoft.Xna.Framework; using System.Collections.Generic; -using System.Linq; namespace Barotrauma { @@ -69,7 +68,7 @@ namespace Barotrauma HumanAIController.ResetEscape(); } HumanAIController.Escape(deltaTime); - if (HumanAIController.EscapeTarget == null || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: false)) + if (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable) { Abandon = true; } @@ -92,14 +91,16 @@ namespace Barotrauma { RemoveSubObjective(ref moveInCaveObjective); RemoveSubObjective(ref moveOutsideObjective); - // TODO: Check 'repeat' and 'onAbandon' parameters TryAddSubObjective(ref moveInsideObjective, constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager), - onCompleted: () => moveInsideObjective = null); + onCompleted: () => RemoveSubObjective(ref moveInsideObjective), + onAbandon: () => Abandon = true); } else { +#if DEBUG DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveInsideObjective'"); +#endif } } } @@ -117,8 +118,7 @@ namespace Barotrauma float closestDistance = float.MaxValue; foreach (var w in WayPoint.WayPointList) { - if (w.Tunnel == null) { continue; } - if (w.Tunnel.Type == Level.TunnelType.Cave) { continue; } + if (w.Tunnel != null && w.Tunnel.Type == Level.TunnelType.Cave) { continue; } if (w.linkedTo.None(l => l is WayPoint linkedWaypoint && linkedWaypoint.Tunnel?.Type == Level.TunnelType.Cave)) { continue; } float distance = Vector2.DistanceSquared(character.WorldPosition, w.WorldPosition); if (closestOutsideWaypoint == null || distance < closestDistance) @@ -131,17 +131,19 @@ namespace Barotrauma { RemoveSubObjective(ref moveInsideObjective); RemoveSubObjective(ref moveOutsideObjective); - // TODO: Check 'repeat' and 'onAbandon' parameters TryAddSubObjective(ref moveInCaveObjective, constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager) { endNodeFilter = n => n.Waypoint == closestOutsideWaypoint }, - onCompleted: () => moveInCaveObjective = null); + onCompleted: () => RemoveSubObjective(ref moveInCaveObjective), + onAbandon: () => Abandon = true); } else { +#if DEBUG DebugConsole.ThrowError("Error with a Return objective: no suitable main or side path node target found for 'moveOutsideObjective'"); +#endif } } else @@ -167,14 +169,16 @@ namespace Barotrauma { RemoveSubObjective(ref moveInsideObjective); RemoveSubObjective(ref moveInCaveObjective); - // TODO: Check 'repeat' and 'onAbandon' parameters TryAddSubObjective(ref moveOutsideObjective, constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager), - onCompleted: () => moveOutsideObjective = null); + onCompleted: () => RemoveSubObjective(ref moveOutsideObjective), + onAbandon: () => Abandon = true); } else { +#if DEBUG DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveOutsideObjective'"); +#endif } } } @@ -182,19 +186,11 @@ namespace Barotrauma { if (HumanAIController.IsInsideCave) { - if (moveOutsideObjective != null) - { - RemoveSubObjective(ref moveOutsideObjective); - moveOutsideObjective = null; - } + RemoveSubObjective(ref moveOutsideObjective); } else { - if (moveInCaveObjective != null) - { - RemoveSubObjective(ref moveInCaveObjective); - moveInCaveObjective = null; - } + RemoveSubObjective(ref moveInCaveObjective); } } usingEscapeBehavior = shouldUseEscapeBehavior; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs index f91b1d36a..57f37a140 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs @@ -119,7 +119,8 @@ namespace Barotrauma public PathFinder(List wayPoints, bool isCharacter) { - nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => (w.Submarine != null == isCharacter) || (isCharacter && w.Tunnel != null)), removeOrphans: true); + var filtered = isCharacter ? wayPoints : wayPoints.FindAll(w => w.Submarine == null); + nodes = PathNode.GenerateNodes(filtered, removeOrphans: true); foreach (WayPoint wp in wayPoints) { wp.OnLinksChanged += WaypointLinksChanged; @@ -179,17 +180,37 @@ namespace Barotrauma foreach (PathNode node in nodes) { node.TempPosition = node.Position; - if (hostSub != null) + var wpSub = node.Waypoint.Submarine; + if (hostSub != null && wpSub == null) { - Vector2 diff = node.Waypoint.Submarine != null ? - hostSub.SimPosition - node.Waypoint.Submarine.SimPosition : - hostSub.SimPosition - node.Waypoint.SimPosition; - node.TempPosition -= diff; + // inside and targeting outside + node.TempPosition -= hostSub.SimPosition; + } + else if (wpSub != null && hostSub != null && wpSub != hostSub) + { + // different subs + node.TempPosition -= hostSub.SimPosition - wpSub.SimPosition; + } + else if (hostSub == null && wpSub != null) + { + // Outside and targeting inside + node.TempPosition += wpSub.SimPosition; } float xDiff = Math.Abs(start.X - node.TempPosition.X); float yDiff = Math.Abs(start.Y - node.TempPosition.Y); - if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) { yDiff += 10.0f; } - node.TempDistance = xDiff + (InsideSubmarine ? yDiff * 10.0f : yDiff); //higher cost for vertical movement when inside the sub + if (InsideSubmarine) + { + //higher cost for vertical movement when inside the sub + if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) + { + yDiff += 10.0f; + } + node.TempDistance = xDiff + yDiff * 10.0f; + } + else + { + node.TempDistance = xDiff + yDiff; + } //much higher cost to waypoints that are outside if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/SteeringManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/SteeringManager.cs index 780ec45e4..d9039091d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/SteeringManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/SteeringManager.cs @@ -57,7 +57,10 @@ namespace Barotrauma public void SteeringManual(float deltaTime, Vector2 velocity) { - steering += velocity; + if (MathUtils.IsValid(velocity)) + { + steering += velocity; + } } public void Reset() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs index 70c639da2..c37d0d8b1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs @@ -374,7 +374,7 @@ namespace Barotrauma { //pull the character's mouth to the target character (again with a fluctuating force) float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f)); - mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength); } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs index 6c964f956..b9aa3d262 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs @@ -746,7 +746,7 @@ namespace Barotrauma var arm = GetLimb(armType); if (arm != null && Math.Abs(arm.body.AngularVelocity) < 10.0f) { - arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f); + arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f * CurrentGroundedParams.ArmMoveStrength); } //get the elbow to a neutral rotation @@ -757,7 +757,7 @@ namespace Barotrauma if (elbow != null) { float diff = elbow.JointAngle - (Dir > 0 ? elbow.LowerLimit : elbow.UpperLimit); - forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f); + forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength); } } } @@ -809,8 +809,8 @@ namespace Barotrauma { foreach (Gap gap in currentHull.ConnectedGaps) { - if (gap.IsHorizontal || gap.Open <= 0.0f) continue; - if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) continue; + if (gap.IsHorizontal || gap.Open <= 0.0f) { continue; } + if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; } //if the gap is above us and leads outside, there's no surface to limit the movement if (!gap.IsRoomToRoom && gap.Position.Y > currentHull.Position.Y) @@ -830,7 +830,7 @@ namespace Barotrauma } } - surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 0.4f) - surfacePos; + surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f) - surfacePos; surfaceLimiter = Math.Max(1.0f, surfaceLimiter); if (surfaceLimiter > 50.0f) { return; } } @@ -921,7 +921,7 @@ namespace Barotrauma head.body.ApplyTorque(Dir); } - movement.Y = movement.Y - (surfaceLimiter - 1.0f) * 0.01f; + movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / 50.0f)); } bool isNotRemote = true; @@ -1003,7 +1003,10 @@ namespace Barotrauma rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X); rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix); float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetRightHandPenalty()), 1.0f); - // Limb hand, Vector2 pos, float force = 1.0f + if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null) + { + speedMultiplier = Math.Min(speedMultiplier, 0.1f); + } HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier); } @@ -1013,6 +1016,10 @@ namespace Barotrauma leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X); leftHandPos = Vector2.Transform(leftHandPos, rotationMatrix); float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetLeftHandPenalty()), 1.0f); + if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null) + { + speedMultiplier = Math.Min(speedMultiplier, 0.1f); + } HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier); } } @@ -1154,7 +1161,7 @@ namespace Barotrauma if (character.SimPosition.Y > ladderSimPos.Y) { climbForce.Y = Math.Min(0.0f, climbForce.Y); } //apply forces to the collider to move the Character up/down - Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass); float movementMultiplier = targetMovement.Y < 0 ? 0 : 1; head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque); @@ -1383,7 +1390,7 @@ namespace Barotrauma target.CharacterHealth.CalculateVitality(); if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f) { - character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive, character.Position + Vector2.UnitY * 150.0f); + character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive); SteamAchievementManager.OnCharacterRevived(target, character); lastReviveTime = (float)Timing.TotalTime; #if SERVER diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index b04947d5a..2a6ece320 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -1348,19 +1348,19 @@ namespace Barotrauma string errorMsg = null; if (!MathUtils.IsValid(body.SimPosition) || Math.Abs(body.SimPosition.X) > 1e10f || Math.Abs(body.SimPosition.Y) > 1e10f) { - errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + "), resetting the ragdoll."; + errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + ")."; } else if (!MathUtils.IsValid(body.LinearVelocity) || Math.Abs(body.LinearVelocity.X) > 1000f || Math.Abs(body.LinearVelocity.Y) > 1000f) { - errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + "), resetting the ragdoll."; + errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + ")."; } else if (!MathUtils.IsValid(body.Rotation)) { - errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + "), resetting the ragdoll."; + errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + ")."; } else if (!MathUtils.IsValid(body.AngularVelocity) || Math.Abs(body.AngularVelocity) > 1000f) { - errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + "), resetting the ragdoll."; + errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + ")."; } if (errorMsg != null) { @@ -1469,11 +1469,11 @@ namespace Barotrauma if (flowForce.LengthSquared() > 0.001f) { - Collider.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + Collider.ApplyForce(flowForce); foreach (Limb limb in limbs) { if (!limb.InWater) { continue; } - limb.body.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + limb.body.ApplyForce(flowForce); } } } @@ -1506,7 +1506,6 @@ namespace Barotrauma if (TorsoPosition.HasValue && MathUtils.IsValid(TorsoPosition.Value)) { height = Math.Max(height, TorsoPosition.Value); } Vector2 rayEnd = rayStart - new Vector2(0.0f, height); - Vector2 onGroundRayEnd = rayStart - Vector2.UnitY * (Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor * 1.2f); Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom()); Fixture standOnFloorFixture = null; @@ -1587,7 +1586,25 @@ namespace Barotrauma if (closestFraction == 1) //raycast didn't hit anything { floorNormal = Vector2.UnitY; - return (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height); + if (CurrentHull == null) + { + return -1000.0f; + } + else + { + float hullBottom = currentHull.Rect.Y - currentHull.Rect.Height; + //check if there's a connected hull below + foreach (var gap in currentHull.ConnectedGaps) + { + if (!gap.IsRoomToRoom || gap.Open < 1.0f || gap.ConnectedDoor != null || gap.IsHorizontal) { continue; } + if (WorldPosition.X > gap.WorldRect.X && WorldPosition.X < gap.WorldRect.Right && gap.WorldPosition.Y < WorldPosition.Y) + { + var lowerHull = gap.linkedTo[0] == currentHull ? gap.linkedTo[1] : gap.linkedTo[0]; + hullBottom = Math.Min(hullBottom, lowerHull.Rect.Y - lowerHull.Rect.Height); + } + } + return ConvertUnits.ToSimUnits(hullBottom); + } } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 8d50256b6..dfc049300 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -1745,8 +1745,12 @@ namespace Barotrauma } else if (IsKeyDown(InputType.Attack)) { - if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && Controlled != this) { + if ((currentAttackTarget.DamageTarget as Entity)?.Removed ?? false) + { + currentAttackTarget = default(AttackTargetData); + } currentAttackTarget.AttackLimb?.UpdateAttack(deltaTime, currentAttackTarget.AttackPos, currentAttackTarget.DamageTarget, out _); } else if (IsPlayer) @@ -3670,16 +3674,14 @@ namespace Barotrauma { float attackerSkillLevel = attacker.GetSkillLevel("weapons"); attacker.Info?.IncreaseSkillLevel("weapons", - -healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f), - attacker.Position + Vector2.UnitY * 100.0f); + -healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f)); } } else if (healthChange > 0.0f) { float attackerSkillLevel = attacker.GetSkillLevel("medical"); attacker.Info?.IncreaseSkillLevel("medical", - healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f), - attacker.Position + Vector2.UnitY * 100.0f); + healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f)); } } @@ -3927,7 +3929,7 @@ namespace Barotrauma } partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log); - public void Revive() + public void Revive(bool removeAllAfflictions = true) { if (Removed) { @@ -3938,7 +3940,14 @@ namespace Barotrauma aiTarget?.Remove(); aiTarget = new AITarget(this); - CharacterHealth.RemoveAllAfflictions(); + if (removeAllAfflictions) + { + CharacterHealth.RemoveAllAfflictions(); + } + else + { + CharacterHealth.RemoveNegativeAfflictions(); + } SetAllDamage(0.0f, 0.0f, 0.0f); Oxygen = 100.0f; Bloodloss = 0.0f; @@ -4284,12 +4293,8 @@ namespace Barotrauma } if (Submarine == null && target.Submarine != null) { - if (AIController == null || !(AIController.SteeringManager is IndoorsSteeringManager)) - { - // outside and targeting inside - // doesn't work with inside steering - targetPos += target.Submarine.SimPosition; - } + // outside and targeting inside + targetPos += target.Submarine.SimPosition; } else if (Submarine != null && target.Submarine == null) { @@ -4376,14 +4381,14 @@ namespace Barotrauma public bool GiveTalent(TalentPrefab talentPrefab, bool addingFirstTime = true) { - if (addingFirstTime) - { - if (!info.UnlockedTalents.Add(talentPrefab.Identifier)) { return false; } - } + if (info == null) { return false; } + info.UnlockedTalents.Add(talentPrefab.Identifier); + if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; } CharacterTalent characterTalent = new CharacterTalent(talentPrefab, this); characterTalent.ActivateTalent(addingFirstTime); characterTalents.Add(characterTalent); + characterTalent.AddedThisRound = addingFirstTime; #if SERVER GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents }); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index 79d154601..741f47897 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -1162,7 +1162,7 @@ namespace Barotrauma return (int)(salary * Job.Prefab.PriceMultiplier); } - public void IncreaseSkillLevel(string skillIdentifier, float increase, Vector2 pos, bool gainedFromApprenticeship = false) + public void IncreaseSkillLevel(string skillIdentifier, float increase, bool gainedFromApprenticeship = false) { if (Job == null || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) || Character == null) { return; } @@ -1190,10 +1190,10 @@ namespace Barotrauma } } - OnSkillChanged(skillIdentifier, prevLevel, newLevel, pos); + OnSkillChanged(skillIdentifier, prevLevel, newLevel); } - public void SetSkillLevel(string skillIdentifier, float level, Vector2 pos) + public void SetSkillLevel(string skillIdentifier, float level) { if (Job == null) { return; } @@ -1201,19 +1201,19 @@ namespace Barotrauma if (skill == null) { Job.Skills.Add(new Skill(skillIdentifier, level)); - OnSkillChanged(skillIdentifier, 0.0f, level, pos); + OnSkillChanged(skillIdentifier, 0.0f, level); } else { float prevLevel = skill.Level; skill.Level = level; - OnSkillChanged(skillIdentifier, prevLevel, skill.Level, pos); + OnSkillChanged(skillIdentifier, prevLevel, skill.Level); } } - partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos); + partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel); - public void GiveExperience(int amount, float popupOffset = 0f, bool isMissionExperience = false) + public void GiveExperience(int amount, bool isMissionExperience = false) { int prevAmount = ExperiencePoints; @@ -1229,7 +1229,7 @@ namespace Barotrauma if (amount < 0) { return; } ExperiencePoints += amount; - OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * (150.0f + popupOffset)); + OnExperienceChanged(prevAmount, ExperiencePoints); } public void SetExperience(int newExperience) @@ -1238,7 +1238,7 @@ namespace Barotrauma int prevAmount = ExperiencePoints; ExperiencePoints = newExperience; - OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * 150.0f); + OnExperienceChanged(prevAmount, ExperiencePoints); } const int BaseExperienceRequired = 50; @@ -1295,7 +1295,7 @@ namespace Barotrauma return BaseExperienceRequired + AddedExperienceRequiredPerLevel * level; } - partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos); + partial void OnExperienceChanged(int prevAmount, int newAmount); public void Rename(string newName) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index 6762db6c3..8a6f55e00 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -206,7 +206,11 @@ namespace Barotrauma public float Stun { get { return stunAffliction.Strength; } - set { stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); } + set + { + if (Character.GodMode) { return; } + stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); + } } public float StunTimer { get; private set; } @@ -629,6 +633,22 @@ namespace Barotrauma CalculateVitality(); } + public void RemoveNegativeAfflictions() + { + // also don't remove genetic effects, even if they're negative + foreach (LimbHealth limbHealth in limbHealths) + { + limbHealth.Afflictions.RemoveAll(a => !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff"); + } + + afflictions.RemoveAll(a => !irremovableAfflictions.Contains(a) && !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff"); + foreach (Affliction affliction in irremovableAfflictions) + { + affliction.Strength = 0.0f; + } + CalculateVitality(); + } + private void AddLimbAffliction(Limb limb, Affliction newAffliction, bool allowStacking = true) { if (!newAffliction.Prefab.LimbSpecific || limb == null) { return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Jobs/JobPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Jobs/JobPrefab.cs index da1952365..5bb3e5286 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Jobs/JobPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Jobs/JobPrefab.cs @@ -68,9 +68,20 @@ namespace Barotrauma } } + public class PreviewItem + { + public readonly string ItemIdentifier; + public readonly bool ShowPreview; + + public PreviewItem(string itemIdentifier, bool showPreview) + { + ItemIdentifier = itemIdentifier; + ShowPreview = showPreview; + } + } + public readonly Dictionary ItemSets = new Dictionary(); - public readonly Dictionary> ItemIdentifiers = new Dictionary>(); - public readonly Dictionary> ShowItemPreview = new Dictionary>(); + public readonly Dictionary> PreviewItems = new Dictionary>(); public readonly List Skills = new List(); public readonly List AutonomousObjectives = new List(); public readonly List AppropriateOrders = new List(); @@ -220,8 +231,7 @@ namespace Barotrauma { case "itemset": ItemSets.Add(variant, subElement); - ItemIdentifiers[variant] = new List(); - ShowItemPreview[variant] = new Dictionary(); + PreviewItems[variant] = new List(); loadItemIdentifiers(subElement, variant); variant++; break; @@ -264,8 +274,7 @@ namespace Barotrauma } else { - ItemIdentifiers[variant].Add(itemIdentifier); - ShowItemPreview[variant][itemIdentifier] = itemElement.GetAttributeBool("showpreview", true); + PreviewItems[variant].Add(new PreviewItem(itemIdentifier, itemElement.GetAttributeBool("showpreview", true))); } loadItemIdentifiers(itemElement, variant); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs index 4ece5fc65..9731b08d5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs @@ -759,6 +759,10 @@ namespace Barotrauma appliedDamageModifiers.AddRange(tempModifiers); } var result = new AttackResult(afflictionsCopy, this, appliedDamageModifiers); + if (result.Afflictions.None()) + { + playSound = false; + } AddDamageProjSpecific(playSound, result); float bleedingDamage = 0; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs index b469d98d5..ff46272dc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs @@ -11,12 +11,12 @@ namespace Barotrauma { public enum AnimationType { - NotDefined, - Walk, - Run, - SwimSlow, - SwimFast, - Crouch + NotDefined = 0, + Walk = 1, + Run = 2, + Crouch = 3, + SwimSlow = 4, + SwimFast = 5 } abstract class GroundedMovementParams : AnimationParams diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Ragdoll/RagdollParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Ragdoll/RagdollParams.cs index fff53e186..ff4f961f9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Ragdoll/RagdollParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Ragdoll/RagdollParams.cs @@ -597,7 +597,7 @@ namespace Barotrauma [Serialize(float.NaN, true, description: "The orientation of the sprite as drawn on the sprite sheet. Overrides the value defined in the Ragdoll settings."), Editable(-360, 360, ValueStep = 90, DecimalCount = 0)] public float SpriteOrientation { get; set; } - [Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")] + [Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")] public LimbType InheritLimbDepth { get; set; } [Serialize(0f, true), Editable(MinValueFloat = 0, MaxValueFloat = 500)] diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionIsAiming.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionIsAiming.cs index 01de01b61..26a04a1a7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionIsAiming.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionIsAiming.cs @@ -12,9 +12,12 @@ namespace Barotrauma.Abilities Ranged = 2 }; + private readonly bool hittingCountsAsAiming; + private readonly WeaponType weapontype; public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement) { + hittingCountsAsAiming = conditionElement.GetAttributeBool("hittingcountsasaiming", false); switch (conditionElement.GetAttributeString("weapontype", "")) { case "melee": @@ -28,7 +31,6 @@ namespace Barotrauma.Abilities protected override bool MatchesConditionSpecific() { - bool aimingCorrectItem = false; if (character.AnimController is HumanoidAnimController animController) { foreach (Item item in character.HeldItems) @@ -36,19 +38,23 @@ namespace Barotrauma.Abilities switch (weapontype) { case WeaponType.Melee: - aimingCorrectItem |= item.GetComponent() != null && animController.IsAimingMelee; + var meleeWeapon = item.GetComponent(); + if (meleeWeapon != null) + { + if (animController.IsAimingMelee || (meleeWeapon.Hitting && hittingCountsAsAiming)) { return true; } + } break; case WeaponType.Ranged: - aimingCorrectItem |= item.GetComponent() != null && animController.IsAiming; + if (animController.IsAiming && item.GetComponent() != null) { return true; } break; default: - aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee; + if (animController.IsAiming || animController.IsAimingMelee) { return true; } break; } } } - return aimingCorrectItem; + return false; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionMission.cs similarity index 100% rename from Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionMission.cs rename to Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionMission.cs diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGainSimultaneousSkill.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGainSimultaneousSkill.cs index 5de3fb85f..43fef2a11 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGainSimultaneousSkill.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGainSimultaneousSkill.cs @@ -16,7 +16,7 @@ namespace Barotrauma.Abilities { if ((abilityObject as IAbilityValue)?.Value is float skillIncrease) { - Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, Character.Position + Vector2.UnitY * 175.0f); + Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease); } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveMissionCount.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveMissionCount.cs deleted file mode 100644 index 629202f93..000000000 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveMissionCount.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Xml.Linq; - -namespace Barotrauma.Abilities -{ - class CharacterAbilityGiveMissionCount : CharacterAbility - { - private readonly int amount; - - public CharacterAbilityGiveMissionCount(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement) - { - amount = abilityElement.GetAttributeInt("amount", 0); - } - - public override void InitializeAbility(bool addingFirstTime) - { - if (!addingFirstTime) { return; } - if (!(GameMain.GameSession?.Campaign is CampaignMode campaign)) { return; } - campaign.Settings.AddedMissionCount += amount; - } - } -} diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityIncreaseSkill.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityIncreaseSkill.cs index 59b532aaf..d93519de0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityIncreaseSkill.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityIncreaseSkill.cs @@ -49,13 +49,12 @@ namespace Barotrauma.Abilities { var skill = character.Info?.Job?.Skills?.GetRandom(); if (skill == null) { return; } - character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f); + character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease); } else { - character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f); + character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease); } - } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityRevive.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityRevive.cs index 317d12487..7ed61e90f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityRevive.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityRevive.cs @@ -13,7 +13,7 @@ namespace Barotrauma.Abilities private void ApplyEffectSpecific() { - Character.Revive(); + Character.Revive(removeAllAfflictions: false); } protected override void ApplyEffect() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityUnlockTree.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityUnlockTree.cs index c9a5f9364..b9f26160c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityUnlockTree.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityUnlockTree.cs @@ -21,6 +21,7 @@ namespace Barotrauma.Abilities { foreach (var talent in talentOption.Talents) { + if (talent == CharacterTalent.Prefab) { continue; } Character.GiveTalent(talent); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityApprenticeship.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityApprenticeship.cs index c6f035c5b..95466f08d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityApprenticeship.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityApprenticeship.cs @@ -14,7 +14,7 @@ namespace Barotrauma.Abilities { if (abilityObject is AbilitySkillGain abilitySkillGain && !abilitySkillGain.GainedFromApprenticeship && abilitySkillGain.Character != Character) { - Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, Character.Position + Vector2.UnitY * 175.0f, gainedFromApprenticeship: true); + Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, gainedFromApprenticeship: true); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityMultitasker.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityMultitasker.cs index b22d35c46..339b5c47f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityMultitasker.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityMultitasker.cs @@ -18,7 +18,7 @@ namespace Barotrauma.Abilities if (skillIdentifier != lastSkillIdentifier) { lastSkillIdentifier = skillIdentifier; - Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f, Character.Position + Vector2.UnitY * 175.0f); + Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/CharacterTalent.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/CharacterTalent.cs index 703a3c852..3a79e1b2a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/CharacterTalent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/CharacterTalent.cs @@ -13,6 +13,8 @@ namespace Barotrauma public readonly TalentPrefab Prefab; + public bool AddedThisRound = true; + private readonly Dictionary> characterAbilityGroupEffectDictionary = new Dictionary>(); private readonly List characterAbilityGroupIntervals = new List(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index a73fb5af0..bc9d3ea89 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -809,13 +809,13 @@ namespace Barotrauma { foreach (Skill skill in character.Info.Job.Skills) { - character.Info.SetSkillLevel(skill.Identifier, level, character.WorldPosition); + character.Info.SetSkillLevel(skill.Identifier, level); } NewMessage($"Set all {character.Name}'s skills to {level}", Color.Green); } else { - character.Info.SetSkillLevel(skillIdentifier, level, character.WorldPosition); + character.Info.SetSkillLevel(skillIdentifier, level); NewMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", Color.Green); } } @@ -839,7 +839,7 @@ namespace Barotrauma NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White); }, isCheat: true)); - commands.Add(new Command("givetalent", "give [player] testing [talent]", (string[] args) => + commands.Add(new Command("givetalent", "givetalent [talent] [player]: give the talent to the specified character. If the character argument is omitted, the talent is given to the controlled character.", (string[] args) => { if (args.Length == 0) { return; } var character = args.Length >= 2 ? FindMatchingCharacter(args.Skip(1).ToArray()) : Character.Controlled; @@ -1886,13 +1886,15 @@ namespace Barotrauma } return; } -#if !DEBUG if (!IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client)) { +#if DEBUG + AddWarning("You're not permitted to use the command \"{matchingCommand.Name}\". Executing the command anyway because this is a debug build."); +#else ThrowError("You're not permitted to use the command \"" + splitCommand[0].ToLowerInvariant() + "\"!"); return; - } #endif + } } #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs index 619a77ea3..b6a3d3d83 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs @@ -119,6 +119,7 @@ MissionMoneyGainMultiplier, ExperienceGainMultiplier, MissionExperienceGainMultiplier, + ExtraMissionCount, ExtraSpecialSalesCount, ApplyTreatmentsOnSelfFraction, MaxAttachableCount, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GiveSkillExpAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GiveSkillExpAction.cs index 8959f518f..2da290284 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GiveSkillExpAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GiveSkillExpAction.cs @@ -40,7 +40,7 @@ namespace Barotrauma var targets = ParentEvent.GetTargets(TargetTag).Where(e => e is Character).Select(e => e as Character); foreach (var target in targets) { - target.Info?.IncreaseSkillLevel(Skill?.ToLowerInvariant(), Amount, target.Position + Vector2.UnitY * 150.0f); + target.Info?.IncreaseSkillLevel(Skill?.ToLowerInvariant(), Amount); } isFinished = true; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AlienRuinMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AlienRuinMission.cs index ad82de75c..993b0cd02 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AlienRuinMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AlienRuinMission.cs @@ -165,12 +165,12 @@ namespace Barotrauma public override void End() { - if (AllTargetsEliminated()) + if (State == 2) { GiveReward(); completed = true; } - failed = !completed && state > 0; + failed = !completed && State > 0; } } } \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs index 410e7da37..c84e43647 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs @@ -18,7 +18,7 @@ namespace Barotrauma private readonly int targetsToScan; private readonly Dictionary scanTargets = new Dictionary(); private readonly HashSet newTargetsScanned = new HashSet(); - private readonly float minTargetDistance, minTargetDistanceSquared; + private readonly float minTargetDistance; private Ruin TargetRuin { get; set; } @@ -58,7 +58,6 @@ namespace Barotrauma itemConfig = prefab.ConfigElement.Element("Items"); targetsToScan = prefab.ConfigElement.GetAttributeInt("targets", 1); minTargetDistance = prefab.ConfigElement.GetAttributeFloat("mintargetdistance", 0.0f); - minTargetDistanceSquared = minTargetDistance * minTargetDistance; } protected override void StartMissionSpecific(Level level) @@ -86,28 +85,57 @@ namespace Barotrauma return; } - var availableWaypoints = TargetRuin.Submarine.GetWaypoints(false); - availableWaypoints.RemoveAll(wp => wp.CurrentHull == null); - if (availableWaypoints.Count < targetsToScan) + var ruinWaypoints = TargetRuin.Submarine.GetWaypoints(false); + ruinWaypoints.RemoveAll(wp => wp.CurrentHull == null); + if (ruinWaypoints.Count < targetsToScan) { - DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({availableWaypoints.Count} < {targetsToScan})"); + DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {targetsToScan})"); return; } - for (int i = 0; i < targetsToScan; i++) + var availableWaypoints = new List(); + float minTargetDistanceSquared = minTargetDistance * minTargetDistance; + for (int tries = 0; tries < 15; tries++) { - var selectedWaypoint = availableWaypoints.GetRandom(randSync: Rand.RandSync.Server); - scanTargets.Add(selectedWaypoint, false); - availableWaypoints.Remove(selectedWaypoint); - if (i < (targetsToScan - 1)) + scanTargets.Clear(); + availableWaypoints.Clear(); + availableWaypoints.AddRange(ruinWaypoints); + for (int i = 0; i < targetsToScan; i++) { - availableWaypoints.RemoveAll(wp => wp.CurrentHull == selectedWaypoint.CurrentHull); - availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < minTargetDistanceSquared); - if (availableWaypoints.None()) + var selectedWaypoint = availableWaypoints.GetRandom(randSync: Rand.RandSync.Server); + scanTargets.Add(selectedWaypoint, false); + availableWaypoints.Remove(selectedWaypoint); + if (i < (targetsToScan - 1)) { - DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})"); - break; + availableWaypoints.RemoveAll(wp => wp.CurrentHull == selectedWaypoint.CurrentHull); + availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < minTargetDistanceSquared); + if (availableWaypoints.None()) + { +#if DEBUG + DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})"); +#endif + break; + } } } + if (scanTargets.Count >= targetsToScan) + { +#if DEBUG + DebugConsole.NewMessage($"Successfully initialized a Scan mission: targets set on try #{tries + 1}", Color.Green); +#endif + break; + } + if ((tries + 1) % 5 == 0) + { + float reducedMinTargetDistance = (1.0f - (((tries + 1) / 5) * 0.1f)) * minTargetDistance; + minTargetDistanceSquared = reducedMinTargetDistance * reducedMinTargetDistance; +#if DEBUG + DebugConsole.NewMessage($"Reducing minimum distance between Scan mission targets (new min: {reducedMinTargetDistance}) to reach the required target count", Color.Yellow); +#endif + } + } + if (scanTargets.Count < targetsToScan) + { + DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {targetsToScan})"); } } @@ -218,7 +246,7 @@ namespace Barotrauma public override void End() { - if (AllTargetsScanned && AllScannersReturned()) + if (State == 2 && AllScannersReturned()) { GiveReward(); completed = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs index 49e0aa705..5aa20f202 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs @@ -489,6 +489,11 @@ namespace Barotrauma continue; } } + if (orderInfo.Order.TargetEntity == null || (orderInfo.Order.IsIgnoreOrder && ignoreTarget == null)) + { + // The order target doesn't exist anymore, just discard the loaded order + continue; + } if (ignoreTarget != null) { ignoreTarget.OrderedToBeIgnored = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs index 49f175753..85a3ef2f4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs @@ -51,7 +51,7 @@ namespace Barotrauma if (reputationChange > 0f) { float reputationGainMultiplier = 1f; - foreach (Character character in Character.CharacterList.Where(c => c.TeamID == CharacterTeamType.Team1)) + foreach (Character character in GameSession.GetSessionCrewCharacters()) { reputationGainMultiplier += character.GetStatValue(StatTypes.ReputationGainMultiplier); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs index e526eebd8..a1dfda365 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs @@ -17,9 +17,7 @@ namespace Barotrauma public static CampaignSettings Unsure = Empty; public bool RadiationEnabled { get; set; } - public int AddedMissionCount { get; set; } - - public int TotalMaxMissionCount => MaxMissionCount + AddedMissionCount; + public int TotalMaxMissionCount => MaxMissionCount + GetAddedMissionCount(); private int maxMissionCount; public int MaxMissionCount @@ -36,7 +34,6 @@ namespace Barotrauma { maxMissionCount = DefaultMaxMissionCount; RadiationEnabled = inc.ReadBoolean(); - AddedMissionCount = inc.ReadInt32(); MaxMissionCount = inc.ReadInt32(); } @@ -44,7 +41,6 @@ namespace Barotrauma { maxMissionCount = DefaultMaxMissionCount; RadiationEnabled = element.GetAttributeBool(nameof(RadiationEnabled).ToLowerInvariant(), true); - AddedMissionCount = element.GetAttributeInt(nameof(AddedMissionCount).ToLowerInvariant(), 0); MaxMissionCount = element.GetAttributeInt(nameof(MaxMissionCount).ToLowerInvariant(), DefaultMaxMissionCount); } @@ -52,12 +48,21 @@ namespace Barotrauma { msg.Write(RadiationEnabled); msg.Write(MaxMissionCount); - msg.Write(AddedMissionCount); + } + + public int GetAddedMissionCount() + { + int count = 0; + foreach (Character character in GameSession.GetSessionCrewCharacters()) + { + count += (int)character.GetStatValue(StatTypes.ExtraMissionCount); + } + return count; } public XElement Save() { - return new XElement(nameof(CampaignSettings), new XAttribute(nameof(RadiationEnabled).ToLowerInvariant(), RadiationEnabled), new XAttribute(nameof(MaxMissionCount).ToLowerInvariant(), MaxMissionCount), new XAttribute(nameof(AddedMissionCount).ToLowerInvariant(), AddedMissionCount)); + return new XElement(nameof(CampaignSettings), new XAttribute(nameof(RadiationEnabled).ToLowerInvariant(), RadiationEnabled), new XAttribute(nameof(MaxMissionCount).ToLowerInvariant(), MaxMissionCount)); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs index afdaf91e6..9523e5299 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs @@ -661,10 +661,10 @@ namespace Barotrauma public static IEnumerable GetSessionCrewCharacters() { #if SERVER - return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null); + return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null && !c.IsDead); #else if (GameMain.GameSession == null) { return Enumerable.Empty(); } - return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null); + return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null && !c.IsDead); #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/EntitySpawnerComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/EntitySpawnerComponent.cs index f73cebac4..ec5f6b078 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/EntitySpawnerComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/EntitySpawnerComponent.cs @@ -49,13 +49,13 @@ namespace Barotrauma.Items.Components [Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 10f), Serialize("0,0", true, "Offset of the spawn area from the center of the item")] public Vector2 SpawnAreaOffset { get; set; } - [Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 1f), Serialize("10,40", true, "Time range between spawn attempts in seconds")] + [Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 1f), Serialize("10,40", true, "Time range between spawn attempts in seconds. Set both to a negative value to disable automatic spawning.")] public Vector2 SpawnTimerRange { get; set; } [Editable(MaxValueFloat = int.MaxValue, MinValueFloat = 1f, ValueStep = 1f, DecimalCount = 0), Serialize("1,3", true, "Minumum and maximum amount of items or creatures to spawn in one attempt")] public Vector2 SpawnAmountRange { get; set; } - [Editable(MinValueInt = 0), Serialize(8, true, "Amount of items or creatures in the spawn area that will prevent further items or creatures from being spawned")] + [Editable(MinValueInt = int.MinValue, MaxValueInt = int.MaxValue), Serialize(8, true, "Amount of items or creatures in the spawn area that will prevent further items or creatures from being spawned")] public int MaximumAmount { get; set; } [Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 10f), Serialize(500f, true, "Inflate the circle of rectangle by this value to extend the area that counts towards the maximum amount of items or enemies to be spawned")] @@ -110,7 +110,12 @@ namespace Barotrauma.Items.Components if (GameMain.NetworkMember is { IsClient: true }) { return; } - SpawnTimerGoal ??= Rand.Range(Math.Min(SpawnTimerRange.X, SpawnTimerRange.Y), Math.Max(SpawnTimerRange.X, SpawnTimerRange.Y), Rand.RandSync.Unsynced); + float minTime = Math.Min(SpawnTimerRange.X, SpawnTimerRange.Y), + maxTime = Math.Max(SpawnTimerRange.X, SpawnTimerRange.Y); + + if (minTime < 0 && maxTime < 0) { return; } + + SpawnTimerGoal ??= Rand.Range(minTime, maxTime, Rand.RandSync.Unsynced); SpawnTimer += deltaTime; @@ -120,12 +125,12 @@ namespace Barotrauma.Items.Components SpawnTimerGoal = null; SpawnTimer = 0; } - } public override void ReceiveSignal(Signal signal, Connection connection) { bool isNonZero = signal.value != "0"; + bool isClient = GameMain.NetworkMember is { IsClient: true }; switch (connection.Name) { @@ -135,6 +140,9 @@ namespace Barotrauma.Items.Components case "toggle" when isNonZero: CanSpawn = !CanSpawn; break; + case "trigger_in" when isNonZero && !isClient: + Spawn(); + break; } } @@ -163,6 +171,8 @@ namespace Barotrauma.Items.Components } } + if (MaximumAmount < 0) { return true; } + int amount; if (!string.IsNullOrWhiteSpace(SpeciesName)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs index 05b87be87..299afe98d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs @@ -59,6 +59,7 @@ namespace Barotrauma.Items.Components [Editable, Serialize("3.0, -1.0", false)] public Vector2 SwingForce { get; set; } + public bool Hitting { get { return hitting; } } /// /// Defines items that boost the weapon functionality, like battery cell for stun batons. diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Propulsion.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Propulsion.cs index 9e6ad682a..39e61fcb0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Propulsion.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Propulsion.cs @@ -66,18 +66,18 @@ namespace Barotrauma.Items.Components foreach (Limb limb in character.AnimController.Limbs) { if (limb.WearingItems.Find(w => w.WearableComponent.Item == item) == null) { continue; } - limb.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + limb.body.ApplyForce(propulsion); } - character.AnimController.Collider.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + character.AnimController.Collider.ApplyForce(propulsion); if (character.Inventory.IsInLimbSlot(item, InvSlotType.RightHand)) { - character.AnimController.GetLimb(LimbType.RightHand)?.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + character.AnimController.GetLimb(LimbType.RightHand)?.body.ApplyForce(propulsion); } if (character.Inventory.IsInLimbSlot(item, InvSlotType.LeftHand)) { - character.AnimController.GetLimb(LimbType.LeftHand)?.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + character.AnimController.GetLimb(LimbType.LeftHand)?.body.ApplyForce(propulsion); } #if CLIENT diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs index 5efe930de..e3eb12bcd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs @@ -200,7 +200,8 @@ namespace Barotrauma.Items.Components void CreateDeconstructProduct(DeconstructItem deconstructProduct, IEnumerable inputItems) { - float percentageHealth = targetItem.Condition / targetItem.Prefab.Health; + float percentageHealth = targetItem.Condition / targetItem.MaxCondition; + if (percentageHealth <= deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) { return; } if (!(MapEntityPrefab.Find(null, deconstructProduct.ItemIdentifier) is ItemPrefab itemPrefab)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs index 528dee25a..461ae0617 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs @@ -391,8 +391,7 @@ namespace Barotrauma.Items.Components user.Info.IncreaseSkillLevel( skill.Identifier, - addedSkill, - user.Position + Vector2.UnitY * 150.0f); + addedSkill); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/OxygenGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/OxygenGenerator.cs index 8e836bcf1..60c93f2a9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/OxygenGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/OxygenGenerator.cs @@ -11,9 +11,12 @@ namespace Barotrauma.Items.Components private float generatedAmount; //key = vent, float = total volume of the hull the vent is in and the hulls connected to it - private Dictionary ventList; + private List<(Vent vent, float hullVolume)> ventList; private float totalHullVolume; + + private float ventUpdateTimer; + const float VentUpdateInterval = 5.0f; public float CurrFlow { @@ -64,7 +67,7 @@ namespace Barotrauma.Items.Components //20% condition = 4% CurrFlow *= conditionMult * conditionMult; - UpdateVents(CurrFlow); + UpdateVents(CurrFlow, deltaTime); } public override void UpdateBroken(float deltaTime, Camera cam) @@ -75,7 +78,8 @@ namespace Barotrauma.Items.Components private void GetVents() { - ventList = new Dictionary(); + ventList ??= new List<(Vent vent, float hullVolume)>(); + ventList.Clear(); foreach (MapEntity entity in item.linkedTo) { if (!(entity is Item linkedItem)) { continue; } @@ -83,30 +87,39 @@ namespace Barotrauma.Items.Components Vent vent = linkedItem.GetComponent(); if (vent?.Item.CurrentHull == null) { continue; } - ventList.Add(vent, 0.0f); - foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: true, searchDepth: 10, ignoreClosedGaps: true)) - { + ventList.Add((vent, vent.Item.CurrentHull.Volume)); + } + + for (int i = 0; i < ventList.Count; i++) + { + Vent vent = ventList[i].vent; + foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: false, searchDepth: 5, ignoreClosedGaps: true)) + { + //another vent in the connected hull -> don't add it to this vent's total hull volume + if (ventList.Any(v => v.vent != vent && v.vent.Item.CurrentHull == connectedHull)) { continue; } totalHullVolume += connectedHull.Volume; - ventList[vent] += connectedHull.Volume; + ventList[i] = (ventList[i].vent, ventList[i].hullVolume + connectedHull.Volume); } } } - - private void UpdateVents(float deltaOxygen) + + private void UpdateVents(float deltaOxygen, float deltaTime) { - if (ventList == null) + if (ventList == null || ventUpdateTimer < 0.0f) { GetVents(); + ventUpdateTimer = VentUpdateInterval; } + ventUpdateTimer -= deltaTime; if (!ventList.Any() || totalHullVolume <= 0.0f) { return; } - foreach (KeyValuePair v in ventList) + foreach ((Vent vent, float hullVolume) in ventList) { - if (v.Key?.Item.CurrentHull == null) { continue; } + if (vent.Item.CurrentHull == null) { continue; } - v.Key.OxygenFlow = deltaOxygen * (v.Value / totalHullVolume); - v.Key.IsActive = true; + vent.OxygenFlow = deltaOxygen * (hullVolume / totalHullVolume); + vent.IsActive = true; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Steering.cs index 0fdba45ca..44e6461b3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Steering.cs @@ -392,8 +392,7 @@ namespace Barotrauma.Items.Components float userSkill = Math.Max(user.GetSkillLevel("helm"), 1.0f) / 100.0f; user.Info.IncreaseSkillLevel( "helm", - SkillSettings.Current.SkillIncreasePerSecondWhenSteering / userSkill * deltaTime, - user.Position + Vector2.UnitY * 150.0f); + SkillSettings.Current.SkillIncreasePerSecondWhenSteering / userSkill * deltaTime); } private void UpdateAutoPilot(float deltaTime) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index 0cfd93de8..f44619825 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -340,7 +340,7 @@ namespace Barotrauma.Items.Components item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange; } - item.Drop(null); + item.Drop(null, createNetworkEvent: false); launchPos = item.SimPosition; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/RemoteController.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/RemoteController.cs index 1903a74c0..783253c89 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/RemoteController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/RemoteController.cs @@ -35,7 +35,6 @@ namespace Barotrauma.Items.Components public RemoteController(Item item, XElement element) : base(item, element) { - DrawHudWhenEquipped = false; } public override bool Select(Character character) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs index 041037cdf..d36c11e6f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs @@ -440,8 +440,7 @@ namespace Barotrauma.Items.Components { float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier); CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier, - SkillSettings.Current.SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f), - CurrentFixer.Position + Vector2.UnitY * 100.0f); + SkillSettings.Current.SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f)); } SteamAchievementManager.OnItemRepaired(item, CurrentFixer); CurrentFixer.CheckTalents(AbilityEffectType.OnRepairComplete); @@ -472,8 +471,7 @@ namespace Barotrauma.Items.Components { float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier); CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier, - SkillSettings.Current.SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f), - CurrentFixer.Position + Vector2.UnitY * 100.0f); + SkillSettings.Current.SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f)); } deteriorationTimer = 0.0f; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs index 197bdd2c4..10ef02bdb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs @@ -159,6 +159,8 @@ namespace Barotrauma.Items.Components ApplyForce(i.body); } } + + item.SendSignal(IsActive ? "1" : "0", "state_out"); } private void ApplyForce(PhysicsBody body) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs index 39d5a30ae..327c23181 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs @@ -438,8 +438,7 @@ namespace Barotrauma.Items.Components if (user?.Info != null && (GameMain.GameSession?.Campaign == null || !Level.IsLoadedOutpost)) { user.Info.IncreaseSkillLevel("weapons", - SkillSettings.Current.SkillIncreasePerSecondWhenOperatingTurret * deltaTime / Math.Max(user.GetSkillLevel("weapons"), 1.0f), - user.Position + Vector2.UnitY * 150.0f); + SkillSettings.Current.SkillIncreasePerSecondWhenOperatingTurret * deltaTime / Math.Max(user.GetSkillLevel("weapons"), 1.0f)); } float rotMidDiff = MathHelper.WrapAngle(rotation - (minRotation + maxRotation) / 2.0f); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Wearable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Wearable.cs index 00a144ba0..2b4190bb4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Wearable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Wearable.cs @@ -46,6 +46,7 @@ namespace Barotrauma public LimbType Limb { get; private set; } public bool HideLimb { get; private set; } public bool HideOtherWearables { get; private set; } + public bool CanBeHiddenByOtherWearables { get; private set; } public List HideWearablesOfType { get; private set; } public bool InheritLimbDepth { get; private set; } /// @@ -176,6 +177,7 @@ namespace Barotrauma Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true); HideLimb = SourceElement.GetAttributeBool("hidelimb", false); HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false); + CanBeHiddenByOtherWearables = SourceElement.GetAttributeBool("canbehiddenbyotherwearables", true); InheritLimbDepth = SourceElement.GetAttributeBool("inheritlimbdepth", true); var scale = SourceElement.GetAttribute("inheritscale"); if (scale != null) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 2d5079340..33a9253af 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1803,7 +1803,7 @@ namespace Barotrauma Vector2 drag = body.LinearVelocity * volume; - body.ApplyForce((uplift - drag) * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + body.ApplyForce((uplift - drag) * 10.0f); //apply simple angular drag body.ApplyTorque(body.AngularVelocity * volume * -0.05f); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index 3378966a4..122eebb5b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -314,6 +314,8 @@ namespace Barotrauma /// public bool IsOverride; + public readonly ItemPrefab VariantOf; + public XElement ConfigElement { get; @@ -783,6 +785,7 @@ namespace Barotrauma } else { + VariantOf = basePrefab; ConfigElement = element = CreateVariantXML(element, basePrefab); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs index c2dd49b6c..ad9b19866 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs @@ -36,6 +36,8 @@ namespace Barotrauma /// public bool ExcludeBroken { get; private set; } + private bool allowVariants = true; + public RelationType Type { get { return type; } @@ -82,13 +84,13 @@ namespace Barotrauma { if (item == null) { return false; } if (excludedIdentifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id))) { return false; } - return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id)); + return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id) || (allowVariants && item.Prefab.VariantOf?.Identifier == id)); } public bool MatchesItem(ItemPrefab itemPrefab) { if (itemPrefab == null) { return false; } if (excludedIdentifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id))) { return false; } - return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id)); + return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id) || (allowVariants && itemPrefab.VariantOf?.Identifier == id)); } public RelatedItem(string[] identifiers, string[] excludedIdentifiers) @@ -168,7 +170,8 @@ namespace Barotrauma new XAttribute("optional", IsOptional), new XAttribute("ignoreineditor", IgnoreInEditor), new XAttribute("excludebroken", ExcludeBroken), - new XAttribute("targetslot", TargetSlot)); + new XAttribute("targetslot", TargetSlot), + new XAttribute("allowvariants", allowVariants)); if (excludedIdentifiers.Length > 0) { @@ -231,7 +234,8 @@ namespace Barotrauma RelatedItem ri = new RelatedItem(identifiers, excludedIdentifiers) { - ExcludeBroken = element.GetAttributeBool("excludebroken", true) + ExcludeBroken = element.GetAttributeBool("excludebroken", true), + allowVariants = element.GetAttributeBool("allowvariants", true) }; string typeStr = element.GetAttributeString("type", ""); if (string.IsNullOrEmpty(typeStr)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs index ba3774838..47093bcf6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs @@ -934,7 +934,7 @@ namespace Barotrauma foreach (var gap in ConnectedGaps.Where(gap => gap.Open > 0)) { var distance = MathHelper.Max(Vector2.DistanceSquared(item.Position, gap.Position) / 1000, 1f); - item.body.ApplyForce((gap.LerpedFlowForce / distance) * deltaTime, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + item.body.ApplyForce((gap.LerpedFlowForce / distance) * deltaTime); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index ac3521e32..c0e618e9d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -1888,7 +1888,10 @@ namespace Barotrauma { for (float x = waypointArea.X + outSideWaypointInterval; x < waypointArea.Right - outSideWaypointInterval; x += outSideWaypointInterval) { - var wayPoint = new WayPoint(new Vector2(x, waypointArea.Y + waypointArea.Height * i), SpawnType.Path, null); + var wayPoint = new WayPoint(new Vector2(x, waypointArea.Y + waypointArea.Height * i), SpawnType.Path, null) + { + Ruin = ruin + }; wayPoints.Add(wayPoint); if (x == waypointArea.X + outSideWaypointInterval) { @@ -1907,7 +1910,10 @@ namespace Barotrauma WayPoint wayPoint = null; for (float y = waypointArea.Y; y < waypointArea.Y + waypointArea.Height; y += outSideWaypointInterval) { - wayPoint = new WayPoint(new Vector2(waypointArea.X + waypointArea.Width * i, y), SpawnType.Path, null); + wayPoint = new WayPoint(new Vector2(waypointArea.X + waypointArea.Width * i, y), SpawnType.Path, null) + { + Ruin = ruin + }; wayPoints.Add(wayPoint); if (y == waypointArea.Y) { @@ -1940,12 +1946,33 @@ namespace Barotrauma //connect ruin entrances to the outside waypoints foreach (Gap g in Gap.GapList) { - if (g.Submarine != ruin.Submarine || g.IsRoomToRoom) { continue; } + if (g.Submarine != ruin.Submarine || g.IsRoomToRoom || g.linkedTo.Count == 0) { continue; } var gapWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == g); if (gapWaypoint == null) { continue; } - var closestWp = FindClosestWayPoint(gapWaypoint.WorldPosition, wayPoints); + + //place another waypoint in front of the entrance + Vector2 entranceDir = Vector2.Zero; + if (g.IsHorizontal) + { + entranceDir = Vector2.UnitX * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X); + } + else + { + entranceDir = Vector2.UnitY * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y); + } + var entranceWayPoint = new WayPoint(g.WorldPosition + entranceDir * 64.0f, SpawnType.Path, null) + { + Ruin = ruin + }; + entranceWayPoint.ConnectTo(gapWaypoint); + var closestWp = FindClosestWayPoint(entranceWayPoint.WorldPosition, wayPoints, (wp) => + { + return Submarine.PickBody( + ConvertUnits.ToSimUnits(wp.WorldPosition), + ConvertUnits.ToSimUnits(entranceWayPoint.WorldPosition), collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) == null; + }); if (closestWp == null) { continue; } - gapWaypoint.ConnectTo(closestWp); + entranceWayPoint.ConnectTo(closestWp); } //create a waypoint path from the ruin to the closest tunnel diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs index 3b401aedb..71a30f339 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs @@ -666,19 +666,19 @@ namespace Barotrauma if (ForceVelocityLimit < 1000.0f) body.ApplyForce(Force * currentForceFluctuation * distFactor, ForceVelocityLimit); else - body.ApplyForce(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + body.ApplyForce(Force * currentForceFluctuation * distFactor); break; case TriggerForceMode.Acceleration: if (ForceVelocityLimit < 1000.0f) body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, ForceVelocityLimit); else - body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor); break; case TriggerForceMode.Impulse: if (ForceVelocityLimit < 1000.0f) body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: ForceVelocityLimit); else - body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor); break; case TriggerForceMode.LimitVelocity: float maxVel = ForceVelocityLimit * currentForceFluctuation * distFactor; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs index aac3655eb..53342d1aa 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs @@ -495,7 +495,7 @@ namespace Barotrauma float GetLevelDifficulty(float areaDifficulty) { const float CurveModifier = 1.5f; - const float DifficultyMultiplier = 1.1f; + const float DifficultyMultiplier = 1.14f; const float BaseDifficulty = -3f; return (float)(1 - Math.Pow(1 - areaDifficulty, CurveModifier)) * DifficultyMultiplier * 100f + BaseDifficulty; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs index 224b41e02..3b0dfa429 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs @@ -77,7 +77,7 @@ namespace Barotrauma locationType = location.GetLocationType(); } - + //load the infos of the outpost module files List outpostModules = new List(); foreach (ContentFile outpostModuleFile in outpostModuleFiles) @@ -85,15 +85,19 @@ namespace Barotrauma var subInfo = new SubmarineInfo(outpostModuleFile.Path); if (subInfo.OutpostModuleInfo != null) { - if (generationParams is RuinGeneration.RuinGenerationParams) - { + if (generationParams is RuinGeneration.RuinGenerationParams) + { //if the module doesn't have the ruin flag or any other flag used in the generation params, don't use it in ruins if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin") && !generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Key))) { continue; } - } + } + else if (subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin")) + { + continue; + } outpostModules.Add(subInfo); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs index e53436daf..5ccf84245 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs @@ -1177,8 +1177,7 @@ namespace Barotrauma if (damageDiff < 0.0f) { attacker.Info?.IncreaseSkillLevel("mechanical", - -damageDiff * SkillSettings.Current.SkillIncreasePerRepairedStructureDamage / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f), - SectionPosition(sectionIndex)); + -damageDiff * SkillSettings.Current.SkillIncreasePerRepairedStructureDamage / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f)); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs index c24088ba5..49bfbf5f6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs @@ -452,7 +452,7 @@ namespace Barotrauma public void ApplyForce(Vector2 force) { - Body.ApplyForce(force, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + Body.ApplyForce(force); } public void SetPosition(Vector2 position) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs index e335f0eec..de504a73e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs @@ -46,6 +46,7 @@ namespace Barotrauma public Hull CurrentHull { get; private set; } public Level.Tunnel Tunnel; + public RuinGeneration.Ruin Ruin; public SpawnType SpawnType { @@ -1097,6 +1098,7 @@ namespace Barotrauma CurrentHull = null; ConnectedGap = null; Tunnel = null; + Ruin = null; Stairs = null; Ladders = null; OnLinksChanged = null; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs index 069c59aed..deb765620 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs @@ -238,7 +238,7 @@ namespace Barotrauma.Networking { byte retval = NetBitWriter.ReadByte(buf, 1, bitPos); bitPos++; - return (retval > 0 ? true : false); + return retval > 0; } internal static void ReadPadBits(byte[] buf, ref int bitPos) @@ -672,14 +672,28 @@ namespace Barotrauma.Networking } } buf = new byte[decompressedData.Length]; - Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length); + try + { + Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length); + } + catch (ArgumentException e) + { + throw new ArgumentException($"Failed to copy the incoming compressed buffer. Source buffer length: {decompressedData.Length}, start position: {0}, length: {decompressedData.Length}, destination buffer length: {buf.Length}.", e); + } lengthBits = decompressedData.Length * 8; DebugConsole.Log("Decompressing message: " + inLength + " to " + LengthBytes); } else { buf = new byte[inBuf.Length]; - Array.Copy(inBuf, startPos, buf, 0, inLength); + try + { + Array.Copy(inBuf, startPos, buf, 0, inLength); + } + catch (ArgumentException e) + { + throw new ArgumentException($"Failed to copy the incoming uncompressed buffer. Source buffer length: {inBuf.Length}, start position: {startPos}, length: {inLength}, destination buffer length: {buf.Length}.", e); + } lengthBits = inLength * 8; } seekPos = 0; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs index 85868e116..81086e854 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs @@ -641,18 +641,9 @@ namespace Barotrauma NetConfig.MaxPhysicsBodyAngularVelocity); } - public void ApplyForce(Vector2 force) + public void ApplyForce(Vector2 force, float maxVelocity = NetConfig.MaxPhysicsBodyVelocity) { - if (!IsValidValue(force, "force", -1e10f, 1e10f)) return; - FarseerBody.ApplyForce(force); - } - - /// - /// Apply a force to the body without increasing it's velocity above a specific limit. - /// - public void ApplyForce(Vector2 force, float maxVelocity) - { - if (!IsValidValue(maxVelocity, "max velocity")) return; + if (!IsValidValue(maxVelocity, "max velocity")) { return; } Vector2 velocityAddition = force / Mass * (float)Timing.Step; Vector2 newVelocity = FarseerBody.LinearVelocity + velocityAddition; @@ -666,20 +657,20 @@ namespace Barotrauma force = velocityAddition.ClampLength(maxVelAddition) * Mass / (float)Timing.Step; } - if (!IsValidValue(force, "clamped force", -1e10f, 1e10f)) return; + if (!IsValidValue(force, "clamped force", -1e10f, 1e10f)) { return; } FarseerBody.ApplyForce(force); } public void ApplyForce(Vector2 force, Vector2 point) { - if (!IsValidValue(force, "force", -1e10f, 1e10f)) return; - if (!IsValidValue(point, "point")) return; + if (!IsValidValue(force, "force", -1e10f, 1e10f)) { return; } + if (!IsValidValue(point, "point")) { return; } FarseerBody.ApplyForce(force, point); } public void ApplyTorque(float torque) { - if (!IsValidValue(torque, "torque")) return; + if (!IsValidValue(torque, "torque")) { return; } FarseerBody.ApplyTorque(torque); } @@ -689,8 +680,8 @@ namespace Barotrauma System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); - if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false; - if (!IsValidValue(rotation, "rotation")) return false; + if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; } + if (!IsValidValue(rotation, "rotation")) { return false; } FarseerBody.SetTransform(simPosition, rotation); if (setPrevTransform) { SetPrevTransform(simPosition, rotation); } @@ -703,8 +694,8 @@ namespace Barotrauma System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); - if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false; - if (!IsValidValue(rotation, "rotation")) return false; + if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; } + if (!IsValidValue(rotation, "rotation")) { return false; } FarseerBody.SetTransformIgnoreContacts(ref simPosition, rotation); if (setPrevTransform) { SetPrevTransform(simPosition, rotation); } @@ -789,7 +780,7 @@ namespace Barotrauma dragForce = Math.Min(drag, Mass * 500.0f) * -velDir; } - ApplyForce(dragForce + buoyancy, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + ApplyForce(dragForce + buoyancy); ApplyTorque(FarseerBody.AngularVelocity * FarseerBody.Mass * -0.08f); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs index 262bbb9c4..c66595a6c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs @@ -32,7 +32,10 @@ namespace Barotrauma { typeof(Rectangle), (str, defVal) => ParseRect(str, true) } }.ToImmutableDictionary(); - public static string ParseContentPathFromUri(this XObject element) => System.IO.Path.GetRelativePath(Environment.CurrentDirectory, element.BaseUri); + public static string ParseContentPathFromUri(this XObject element) + => !string.IsNullOrWhiteSpace(element.BaseUri) + ? System.IO.Path.GetRelativePath(Environment.CurrentDirectory, element.BaseUri.CleanUpPath()) + : ""; public static readonly XmlReaderSettings ReaderSettings = new XmlReaderSettings { diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 2c8cf176c..0100a166f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -1290,7 +1290,7 @@ namespace Barotrauma Character targetCharacter = CharacterFromTarget(target); if (targetCharacter != null && !targetCharacter.Removed) { - targetCharacter?.Info?.GiveExperience(giveExperience, popupOffset: i * 25f); + targetCharacter?.Info?.GiveExperience(giveExperience); i++; } } @@ -1309,7 +1309,7 @@ namespace Barotrauma // don't let clients simulate random skill gain continue; } - targetCharacter.Info?.IncreaseSkillLevel(GetRandomSkill(), amount, targetCharacter.Position + Vector2.UnitY * (150.0f + i * 25f)); + targetCharacter.Info?.IncreaseSkillLevel(GetRandomSkill(), amount); string GetRandomSkill() { @@ -1318,9 +1318,8 @@ namespace Barotrauma } else { - targetCharacter.Info?.IncreaseSkillLevel(skillIdentifier?.ToLowerInvariant(), amount, targetCharacter.Position + Vector2.UnitY * (150.0f + i * 25f)); + targetCharacter.Info?.IncreaseSkillLevel(skillIdentifier?.ToLowerInvariant(), amount); } - i++; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs index 8d727bee0..de832af9f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs @@ -633,7 +633,12 @@ namespace Barotrauma { if (string.IsNullOrEmpty(path)) { return ""; } - path = path.Replace('\\', '/'); + path = path + .Replace('\\', '/'); + if (path.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) + { + path = path.Substring("file:".Length); + } while (path.IndexOf("//") >= 0) { path = path.Replace("//", "/"); diff --git a/Barotrauma/BarotraumaShared/Submarines/Azimuth.sub b/Barotrauma/BarotraumaShared/Submarines/Azimuth.sub index 73038ebb9..e41b82691 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Azimuth.sub and b/Barotrauma/BarotraumaShared/Submarines/Azimuth.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 94ea2fd37..ea0bd0231 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,43 @@ +--------------------------------------------------------------------------------------------------------- +v0.1500.7.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). + --------------------------------------------------------------------------------------------------------- v0.1500.6.0 ---------------------------------------------------------------------------------------------------------