diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TalentMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TalentMenu.cs index 6ddc6a467..871dd8133 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TalentMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TalentMenu.cs @@ -1047,6 +1047,8 @@ namespace Barotrauma showCaseClosureQueue.Enqueue(identifier); } } + + NetLobbyScreen.UpdateJobVariantSelectionIfNeeded(); } private static bool IsOwnCharacter(CharacterInfo? info) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs index 9a8190095..9d5e944fd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -879,6 +879,8 @@ namespace Barotrauma { if (requireCorrectRoundId && roundId != campaign.RoundID) { + //set update flag anyway so we can tell the server we received this data and it won't need to keep resending it + campaign.SetLastUpdateIdForFlag(flag, id); DebugConsole.Log($"Received campaing update for a different round (client: {campaign.RoundID}, server: {roundId}), ignoring..."); return false; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/FireSource.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/FireSource.cs index 1da57e028..90e1b2c2a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/FireSource.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/FireSource.cs @@ -1,4 +1,4 @@ -using Barotrauma.Lights; +using Barotrauma.Lights; using Barotrauma.Particles; using Microsoft.Xna.Framework; using System; @@ -13,21 +13,14 @@ namespace Barotrauma partial void UpdateProjSpecific(float growModifier, float deltaTime) { - if (this is DummyFireSource) - { - EmitParticles(size, WorldPosition, deltaTime, hull, growModifier, null); - } - else - { - EmitParticles(size, WorldPosition, deltaTime, hull, growModifier, OnChangeHull); - } + EmitParticles(size, WorldPosition, deltaTime, hull, growModifier); lightSource.Color = new Color(1.0f, 0.45f, 0.3f) * Rand.Range(0.8f, 1.0f); if (Math.Abs((lightSource.Range * 0.2f) - Math.Max(size.X, size.Y)) > 1.0f) { lightSource.Range = Math.Max(size.X, size.Y) * 5.0f; } if (Vector2.DistanceSquared(lightSource.Position, position) > 5.0f) { lightSource.Position = position + Vector2.UnitY * 30.0f; } } - public void EmitParticles(Vector2 size, Vector2 worldPosition, float deltaTime, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null) + public void EmitParticles(Vector2 size, Vector2 worldPosition, float deltaTime, Hull hull, float growModifier) { var particlePrefab = ParticleManager.FindPrefab("flame"); if (particlePrefab == null) { return; } @@ -54,9 +47,6 @@ namespace Barotrauma if (particle == null) { continue; } - //make some of the particles create another firesource when they enter another hull - if (Rand.Int(20) == 1) { particle.OnChangeHull = onChangeHull; } - particle.Size *= MathHelper.Clamp(size.X / 60.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f); if (Rand.Int(5) == 1) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs index c4fb4318d..4c6eee08a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs @@ -394,6 +394,10 @@ namespace Barotrauma Rectangle fireSourceRect = new Rectangle((int)fs.WorldPosition.X, -(int)fs.WorldPosition.Y, (int)fs.Size.X, (int)fs.Size.Y); GUI.DrawRectangle(spriteBatch, fireSourceRect, GUIStyle.Red, false, 0, 5); GUI.DrawRectangle(spriteBatch, new Rectangle(fireSourceRect.X - (int)fs.DamageRange, fireSourceRect.Y, fireSourceRect.Width + (int)fs.DamageRange * 2, fireSourceRect.Height), GUIStyle.Orange, false, 0, 5); + + Vector2 topCenter = new Vector2(fireSourceRect.Center.X, fireSourceRect.Y); + GUI.DrawLine(spriteBatch, topCenter, topCenter - Vector2.UnitY * fs.FlameHeight, GUIStyle.Red * 0.7f, width: 5); + //GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true); } foreach (FireSource fs in FakeFireSources) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index c542c7ccb..e871f9430 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -18,7 +18,7 @@ namespace Barotrauma private GUIButton serverLogReverseButton; private GUIListBox serverLogBox, serverLogFilterTicks; - private GUIComponent jobVariantTooltip; + private static GUIComponent jobVariantTooltip; private GUIComponent playStyleIconContainer; @@ -2876,7 +2876,7 @@ namespace Barotrauma }; } - private void CreateJobVariantTooltip(JobPrefab jobPrefab, CharacterTeamType team, int variant, bool isPvPMode, GUIComponent parentSlot) + private static void CreateJobVariantTooltip(JobPrefab jobPrefab, CharacterTeamType team, int variant, bool isPvPMode, GUIComponent parentSlot) { jobVariantTooltip = new GUIFrame(new RectTransform(new Point((int)(400 * GUI.Scale), (int)(180 * GUI.Scale)), GUI.Canvas, pivot: Pivot.BottomRight), style: "GUIToolTip") @@ -4111,20 +4111,28 @@ namespace Barotrauma JobSelectionFrame.Visible = false; } - if (GUI.MouseOn?.UserData is JobVariant jobPrefab && + UpdateJobVariantSelectionIfNeeded(); + } + + public static void UpdateJobVariantSelectionIfNeeded() + { + if (GUI.MouseOn?.UserData is JobVariant jobPrefab && GUI.MouseOn.Style?.Name == "JobVariantButton" && GUI.MouseOn.Parent != null) { - if (jobVariantTooltip?.UserData is not JobVariant prevVisibleVariant || - prevVisibleVariant.Prefab != jobPrefab.Prefab || + bool isMultiplayer = GameMain.NetLobbyScreen != null && GameMain.NetworkMember != null; + var teamPreference = isMultiplayer ? GameMain.NetLobbyScreen.TeamPreference : CharacterTeamType.Team1; + var isPvPMode = isMultiplayer ? GameMain.NetLobbyScreen.SelectedMode == GameModePreset.PvP : false; + if (jobVariantTooltip?.UserData is not JobVariant prevVisibleVariant || + prevVisibleVariant.Prefab != jobPrefab.Prefab || prevVisibleVariant.Variant != jobPrefab.Variant) { - CreateJobVariantTooltip(jobPrefab.Prefab, TeamPreference, jobPrefab.Variant, isPvPMode: SelectedMode == GameModePreset.PvP, GUI.MouseOn.Parent); + CreateJobVariantTooltip(jobPrefab.Prefab, teamPreference, jobPrefab.Variant, isPvPMode, GUI.MouseOn.Parent); } } if (jobVariantTooltip != null) { - jobVariantTooltip?.AddToGUIUpdateList(); + jobVariantTooltip?.AddToGUIUpdateList(order: 1); Rectangle mouseRect = jobVariantTooltip.MouseRect; mouseRect.Inflate(60 * GUI.Scale, 60 * GUI.Scale); if (!mouseRect.Contains(PlayerInput.MousePosition)) { jobVariantTooltip = null; } @@ -4547,7 +4555,7 @@ namespace Barotrauma team: TeamPreference, isPvPMode: SelectedMode == GameModePreset.PvP, selectedByPlayer: false); - if (images != null && images.Length > 1) + if (images != null && images.Length > 0) { jobPrefab.Variant = Math.Min(jobPrefab.Variant, images.Length); int currVisible = jobPrefab.Variant; @@ -5055,9 +5063,8 @@ namespace Barotrauma for (int variantIndex = 0; variantIndex < images.Length; variantIndex++) { int selectedVariantIndex = Math.Min(jobPrefab.Variant, images.Length); - images[variantIndex].Visible = images.Length == 1 || selectedVariantIndex == variantIndex; - - if (images.Length > 1) + images[variantIndex].Visible = images.Length == 1 || selectedVariantIndex == variantIndex; + if (images.Length > 0) { var variantButton = CreateJobVariantButton(jobPrefab, variantIndex, images.Length, slot); variantButton.OnClicked = (btn, obj) => diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index a74d951ea..57c513e64 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 68e4ead38..8d6d1ec3e 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 9fdd3d7ee..e5cc41a0c 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index a23bc052b..94fe600dc 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index a0edcea3f..6d8948212 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 8e304e710..e13ec2825 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -2406,7 +2406,8 @@ namespace Barotrauma.Networking settingsBytes = outmsg.LengthBytes - settingsBytes; int campaignBytes = outmsg.LengthBytes; - if (outmsg.LengthBytes < MsgConstants.MTU - 500 && + bool hasSpaceForCampaignData = outmsg.LengthBytes < MsgConstants.MTU - 500; + if (hasSpaceForCampaignData && GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode) { outmsg.WriteBoolean(true); @@ -2417,6 +2418,10 @@ namespace Barotrauma.Networking { outmsg.WriteBoolean(false); outmsg.WritePadBits(); + if (!hasSpaceForCampaignData) + { + DebugConsole.Log($"Not enough space to fit campaign data in the lobby update (length {outmsg.LengthBytes} bytes), omitting..."); + } } campaignBytes = outmsg.LengthBytes - campaignBytes; @@ -2427,6 +2432,10 @@ namespace Barotrauma.Networking { WriteClientList(segmentTable, c, outmsg); } + else + { + DebugConsole.Log($"Not enough space to fit client list in the lobby update (length {outmsg.LengthBytes} bytes), omitting..."); + } clientListBytes = outmsg.LengthBytes - clientListBytes; int chatMessageBytes = outmsg.LengthBytes; diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index eaedcddca..dcaa4c558 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.8.7.0 + 1.8.8.1 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs index fea80a297..e27bf7a04 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs @@ -550,14 +550,14 @@ namespace Barotrauma if (subObjective.IsCompleted) { #if DEBUG - DebugConsole.NewMessage($"{character.Name}: Removing SUBobjective {subObjective.DebugTag} of {DebugTag}, because it is completed.", Color.LightGreen); + DebugConsole.NewMessage($"{character.Name}: Removing subObjective \"{subObjective.DebugTag}\" of \"{DebugTag}\", because it is completed.", Color.LightGreen); #endif subObjectives.Remove(subObjective); } else if (!subObjective.CanBeCompleted) { #if DEBUG - DebugConsole.NewMessage($"{character.Name}: Removing SUBobjective {subObjective.DebugTag} of {DebugTag}, because it cannot be completed.", Color.Red); + DebugConsole.NewMessage($"{character.Name}: Removing subObjective \"{subObjective.DebugTag}\" of \"{DebugTag}\", because it cannot be completed.", Color.Red); #endif subObjectives.Remove(subObjective); if (AbandonWhenCannotCompleteSubObjectives) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs index e63a46765..57e4f73e4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -12,6 +12,7 @@ namespace Barotrauma class AIObjectiveGetItem : AIObjective { public override Identifier Identifier { get; set; } = "get item".ToIdentifier(); + public override string DebugTag => $"{Identifier} ({(IdentifiersOrTags == null || IdentifiersOrTags.None() ? "none" : string.Join(", ", IdentifiersOrTags))})"; public override bool AbandonWhenCannotCompleteSubObjectives => false; public override bool AllowMultipleInstances => true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index 26cae185b..fc7126801 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -10,6 +10,7 @@ namespace Barotrauma class AIObjectiveGoTo : AIObjective { public override Identifier Identifier { get; set; } = "go to".ToIdentifier(); + public override string DebugTag => $"{Identifier} ({Target?.ToString() ?? "none"})"; public override bool KeepDivingGearOn => GetTargetHull() == null; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs index 3c024b878..ad38f8cee 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs @@ -10,7 +10,7 @@ namespace Barotrauma class AIObjectiveOperateItem : AIObjective { public override Identifier Identifier { get; set; } = "operate item".ToIdentifier(); - public override string DebugTag => $"{Identifier} {component.Name}"; + public override string DebugTag => $"{Identifier} ({component.Name})"; public override bool AllowAutomaticItemUnequipping => true; public override bool AllowMultipleInstances => true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs index b5b6efdd2..72fa4a870 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -10,6 +10,8 @@ namespace Barotrauma { public override Identifier Identifier { get; set; } = "repair item".ToIdentifier(); + public override string DebugTag => $"{Identifier} ({Item?.Name ?? "null"})"; + protected override bool AllowInFriendlySubs => true; public override bool KeepDivingGearOn => Item?.CurrentHull == null; protected override bool AllowWhileHandcuffed => false; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs index 2b43cbefb..31e01fc53 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs @@ -206,19 +206,21 @@ namespace Barotrauma { float xDiff = Math.Abs(start.X - node.TempPosition.X); float yDiff = Math.Abs(start.Y - node.TempPosition.Y); + //higher cost for vertical movement when inside the sub if (InsideSubmarine && !(node.Waypoint.Submarine?.Info?.IsRuin ?? false)) { - //higher cost for vertical movement when inside the sub if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) { yDiff += 10.0f; } - node.TempDistance = xDiff + yDiff * 10.0f; - } - else - { - node.TempDistance = xDiff + yDiff; + //only apply the higher cost for vertical movement if it's more than a meter + //(small differences can be caused by non-meaningful variance in the vertical position of the waypoint, we only care about actually going up/down e.g. ladders or stairs) + if (Math.Abs(yDiff) > 1.0f) + { + yDiff *= 10.0f; + } } + 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/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 19b4c12fd..e3c2abb90 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -2926,7 +2926,7 @@ namespace Barotrauma Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, spawnPosition, humanPrefab.CreateCharacterInfo(), onSpawn: newCharacter => { newCharacter.HumanPrefab = humanPrefab; - AddToCrew(newCharacter); + SetTeamAndCrew(newCharacter); humanPrefab.GiveItems(newCharacter, newCharacter.Submarine, spawnPoint); humanPrefab.InitializeCharacter(newCharacter); #if SERVER @@ -2942,7 +2942,7 @@ namespace Barotrauma CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: job, variant: variant); Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, spawnPosition, characterInfo, onSpawn: newCharacter => { - AddToCrew(newCharacter); + SetTeamAndCrew(newCharacter); newCharacter.GiveJobItems(isPvPMode: GameMain.GameSession?.GameMode is PvPMode, spawnPoint); newCharacter.GiveIdCardTags(spawnPoint); newCharacter.Info.StartItemsGiven = true; @@ -2950,10 +2950,13 @@ namespace Barotrauma } else if (CharacterPrefab.FindBySpeciesName(args[0].ToIdentifier()) is { } prefab) { - Entity.Spawner.AddCharacterToSpawnQueue(args[0].ToIdentifier(), spawnPosition, prefab.HasCharacterInfo ? new CharacterInfo(prefab.Identifier) : null); + Entity.Spawner.AddCharacterToSpawnQueue(args[0].ToIdentifier(), spawnPosition, prefab.HasCharacterInfo ? new CharacterInfo(prefab.Identifier) : null, onSpawn: newCharacter => + { + SetTeamAndCrew(newCharacter); + }); } - void AddToCrew(Character newCharacter) + void SetTeamAndCrew(Character newCharacter) { newCharacter.TeamID = teamType; if (addToCrew) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GoTo.cs index 7df0cc135..aac60f667 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/GoTo.cs @@ -1,7 +1,7 @@ namespace Barotrauma { /// - /// Makes the event jump to a somewhere else in the event. + /// Makes the event jump to a somewhere else in the event. Note that using GoTo resets the effects of other, currently active EventActions (e.g. closing conversation prompts and stopping the objectives NPCs were forced to do using actions such as CombatAction or NPCWaitAction). /// class GoTo : EventAction { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs index 8ef56a088..a070e9a96 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs @@ -635,6 +635,8 @@ namespace Barotrauma.Items.Components autoInjectCooldown -= deltaTime; if (autoInjectCooldown <= 0.0f && ownerInventory?.Owner is Character ownerCharacter && + //no point in trying to heal if the character is already dead + !ownerCharacter.IsDead && ownerCharacter.HealthPercentage / 100f <= AutoInjectThreshold && ownerCharacter.HasEquippedItem(item)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index 16617e483..7e5073bd1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -399,7 +399,7 @@ namespace Barotrauma.Items.Components LaunchSub = item.Submarine; //set the rotation of the projectile again because dropping the projectile in Use //resets the rotation and moves it to the position of the parent item - Item.SetTransform(simPosition, rotation + (Item.body.Dir * LaunchRotationRadians), findNewHull: false); + Item.SetTransform(simPosition, GetLaunchRotation(rotation), findNewHull: false); if (DeactivationTime > 0) { deactivationTimer = DeactivationTime; @@ -489,12 +489,7 @@ namespace Barotrauma.Items.Components float modifiedLaunchImpulse = (LaunchImpulse + launchImpulseModifier) * (1 + Rand.Range(-ImpulseSpread, ImpulseSpread)); DoLaunch(launchDir * modifiedLaunchImpulse); //needs to be set after DoLaunch, because dropping the item resets the rotation and dir - float afterLaunchAngle = launchAngle + (item.body.Dir * LaunchRotationRadians); - if (item.body.Dir < 0) - { - afterLaunchAngle -= MathHelper.Pi; - } - item.SetTransform(item.body.SimPosition, afterLaunchAngle, findNewHull: false); + item.SetTransform(item.body.SimPosition, GetLaunchRotation(launchAngle), findNewHull: false); } } User = character; @@ -502,6 +497,20 @@ namespace Barotrauma.Items.Components return true; } + /// + /// Gets the final rotation of the projectile after being launched, taking + /// and the orientation of the projectile's physics body into account. + /// + private float GetLaunchRotation(float unmodifiedLaunchRotation) + { + float launchRotation = unmodifiedLaunchRotation + (item.body.Dir * LaunchRotationRadians); + if (item.body.Dir < 0) + { + launchRotation -= MathHelper.Pi; + } + return launchRotation; + } + public override bool Use(float deltaTime, Character character = null) => Use(character); private void DoLaunch(Vector2 impulse) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/FireSource.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/FireSource.cs index 3fa6c8e18..c1f8f335d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/FireSource.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/FireSource.cs @@ -1,5 +1,4 @@ -using Barotrauma.Networking; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using Barotrauma.Extensions; @@ -19,6 +18,15 @@ namespace Barotrauma const float GrowSpeed = 20.0f; const float MaxDamageRange = 250.0f; + /// + /// How often the FireSource checks whether it can spread to nearby hulls. + /// + const float SpreadToOtherHullsInterval = 5.0f; + /// + /// The probability of the fire spreading to a nearby hull when the check is made. + /// + const float SpreadToOtherHullsProbability = 0.15f; + protected Hull hull; protected Vector2 position; @@ -69,6 +77,12 @@ namespace Barotrauma get { return Math.Min((float)Math.Sqrt(size.X) * 10.0f, MaxDamageRange); } } + /// + /// Affects how far above the fire source things can get damaged and how far above a gap can be for the fire to spread through it. + /// An arbitrary value chosen roughly based on how high the flame particles seem to extend. + /// + public float FlameHeight => MathHelper.Clamp(size.X * 3, 50.0f, 400.0f); + public bool DamagesItems { get; @@ -96,6 +110,8 @@ namespace Barotrauma /// public readonly Character SourceCharacter; + private float spreadToOtherHullsTimer; + public FireSource(Vector2 worldPosition, Hull spawningHull = null, Character sourceCharacter = null, bool isNetworkMessage = false) { hull = Hull.FindHull(worldPosition, spawningHull); @@ -219,7 +235,7 @@ namespace Barotrauma if (removed) { return; } } - if (!(this is DummyFireSource)) + if (this is not DummyFireSource) { ReduceOxygen(deltaTime); } @@ -236,7 +252,14 @@ namespace Barotrauma LimitSize(); - if (size.X > 256.0f && !(this is DummyFireSource)) + spreadToOtherHullsTimer -= deltaTime; + if (spreadToOtherHullsTimer <= 0.0f) + { + TrySpreadToNearbyHulls(); + spreadToOtherHullsTimer = SpreadToOtherHullsInterval; + } + + if (size.X > 256.0f && this is not DummyFireSource) { if (burnDecals.Count == 0) { @@ -262,7 +285,6 @@ namespace Barotrauma } UpdateProjSpecific(growModifier, deltaTime); - if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)) { @@ -270,6 +292,57 @@ namespace Barotrauma } } + /// + /// Makes the fire source attempt to spread to nearby hulls through gaps the firesource is in contact with. + /// The probability of spreading is affected by . + /// + private void TrySpreadToNearbyHulls() + { + foreach (var gap in hull.ConnectedGaps) + { + if (!gap.IsRoomToRoom || gap.Open <= 0.0f) { continue; } + + //no need for any syncing here, server lets the clients know if new fire sources spawn + if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Unsynced) > SpreadToOtherHullsProbability) { continue; } + + if (gap.linkedTo.Where(h => h != hull).FirstOrDefault() is not Hull otherHull) { continue; } + + //if firesource intersects with the gap + if (position.X > gap.Rect.Right) { continue; } + if (position.X + size.X < gap.Rect.X) { continue; } + if (position.Y + FlameHeight < gap.Rect.Y - gap.Rect.Height) { continue; } + if (position.Y - size.Y > gap.Rect.Y) { continue; } + + //how far into the other hull should the firesource spawn + float spawnOffset = 20.0f; + Vector2 fireSourcePos = gap.WorldPosition; + if (gap.IsHorizontal) + { + if (otherHull.Position.X < hull.Position.X) + { + fireSourcePos.X = otherHull.WorldRect.Right - spawnOffset; + } + else if (otherHull.Position.X > hull.Position.X) + { + fireSourcePos.X = otherHull.WorldRect.X + spawnOffset; + } + } + else + { + fireSourcePos.X = MathHelper.Clamp(fireSourcePos.X, position.X, position.X + size.X); + if (otherHull.Position.Y > hull.Position.Y) + { + fireSourcePos.Y = otherHull.WorldRect.Y - otherHull.WorldRect.Height + spawnOffset; + } + else if (otherHull.Position.Y < hull.Position.Y) + { + fireSourcePos.Y = otherHull.WorldRect.Y - spawnOffset; + } + } + new FireSource(fireSourcePos, spawningHull: otherHull); + } + } + protected virtual void ReduceOxygen(float deltaTime) { hull.Oxygen -= size.X * deltaTime * OxygenConsumption; @@ -282,16 +355,6 @@ namespace Barotrauma partial void UpdateProjSpecific(float growModifier, float deltaTime); - private void OnChangeHull(Vector2 pos, Hull particleHull) - { - if (particleHull == hull || particleHull == null) return; - - //hull already has a firesource roughly at the particles position -> don't create a new one - if (particleHull.FireSources.Find(fs => pos.X > fs.position.X - 100.0f && pos.X < fs.position.X + fs.size.X + 100.0f) != null) return; - - new FireSource(new Vector2(pos.X, particleHull.WorldRect.Y - particleHull.Rect.Height + 5.0f)); - } - private void DamageCharacters(float deltaTime) { if (size.X <= 0.0f) { return; } @@ -304,7 +367,7 @@ namespace Barotrauma if (!IsInDamageRange(c, DamageRange)) { continue; } //GetApproximateDistance returns float.MaxValue if there's no path through open gaps between the hulls (e.g. if there's a door/wall in between) - if (hull.GetApproximateDistance(Position, c.Position, c.CurrentHull, 10000.0f) > size.X + DamageRange) + if (hull.GetApproximateDistance(Position, c.Position, c.CurrentHull, 10000.0f) > size.X + DamageRange + FlameHeight) { continue; } @@ -330,16 +393,16 @@ namespace Barotrauma public bool IsInDamageRange(Character c, float damageRange) { - if (c.Position.X < position.X - damageRange || c.Position.X > position.X + size.X + damageRange) return false; - if (c.Position.Y < position.Y - size.Y || c.Position.Y > hull.Rect.Y) return false; + if (c.Position.X < position.X - damageRange || c.Position.X > position.X + size.X + damageRange) { return false; } + if (c.Position.Y < position.Y - size.Y || c.Position.Y > Math.Max(hull.Rect.Y, position.Y + FlameHeight)) { return false; } return true; } public bool IsInDamageRange(Vector2 worldPosition, float damageRange) { - if (worldPosition.X < WorldPosition.X - damageRange || worldPosition.X > WorldPosition.X + size.X + damageRange) return false; - if (worldPosition.Y < WorldPosition.Y - size.Y || worldPosition.Y > hull.WorldRect.Y) return false; + if (worldPosition.X < WorldPosition.X - damageRange || worldPosition.X > WorldPosition.X + size.X + damageRange) { return false; } + if (worldPosition.Y < WorldPosition.Y - size.Y || worldPosition.Y > Math.Max(hull.WorldRect.Y, WorldPosition.Y + FlameHeight)) { return false; } return true; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 0b1affb75..6980ef045 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -2250,9 +2250,14 @@ namespace Barotrauma //(otherwise e.g. a character with 1000 vitality would only get a tenth of the strength) float afflictionStrength = affliction.Strength * (newCharacter.MaxVitality / 100.0f); - Limb afflictionLimb = character.CharacterHealth.GetAfflictionLimb(affliction) ?? character.AnimController.MainLimb; - Limb newAfflictionLimb = newCharacter.AnimController.GetLimb(afflictionLimb.type) ?? newCharacter.AnimController.MainLimb; - + Limb newAfflictionLimb = newCharacter.AnimController.MainLimb; + //if the character has been already removed (some weird statuseffect setup, one effect removes the character before another tries to replace it with something else?) + //we can't find the limbs any more and need go with the main limb + if (!character.Removed) + { + Limb afflictionLimb = character.CharacterHealth.GetAfflictionLimb(affliction) ?? character.AnimController.MainLimb; + newAfflictionLimb = newCharacter.AnimController.GetLimb(afflictionLimb.type) ?? newCharacter.AnimController.MainLimb; + } newCharacter.CharacterHealth.ApplyAffliction(newAfflictionLimb, affliction.Prefab.Instantiate(afflictionStrength)); } } diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index e719bc6a3..0c63ae6ec 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,4 +1,24 @@ ------------------------------------------------------------------------------------------------------------------------------------------------- +v1.8.8.1 +------------------------------------------------------------------------------------------------------------------------------------------------- + +- Fixed client list often appearing empty in the server lobby when joining mid-round while a campaign was active. +- Fixed job variant selection panel rendering below the job selection panel, often making it unusable. +- Fixed job variant selection only working in the server lobby, not in the tab menu mid-round. +- Fixed inability to preview loadouts if there's only one variant of a job available (e.g. assistants). +- Fixed fires no longer spreading from room to room. +- Fixed a pathfinding issue that sometimes caused both to get stuck running back and forth towards the target they're trying to reach (one common place where this occurred was Barsuk's engine room). +- Fixed non-hitscan projectiles such as harpoons launching with an incorrect rotation when fired to the left. +- Fixed Herja not having any assistant or non-job-specific spawnpoints, causing assistants and custom classes to spawn at other classes' spawnpoints, potentially giving them ID card tags they shouldn't have. +- Autoinjectors no longer inject meds on dead characters (even though they are technically below the health threshold at which the autoinjection should trigger). +- Fixed team argument not working on the "spawncharacter" console command when spawning non-humans. +- Fixed some edge chunk objects in hydrothermal wastes and the great sea spawning in front of the level walls. +- Fixed missing gap in one of the new crew modules, which prevented water and oxygen from flowing through the module properly. + +Modding: +- Fixed transferring afflictions to a newly spawned character using status effects causing a crash if the original character had already been removed. Didn't affect any vanilla content. + +------------------------------------------------------------------------------------------------------------------------------------------------- v1.8.7.0 -------------------------------------------------------------------------------------------------------------------------------------------------