diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Projectile.cs index 7993a8a97..fd794ea11 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Projectile.cs @@ -21,9 +21,11 @@ namespace Barotrauma.Items.Components Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle()); float rotation = msg.ReadSingle(); spreadIndex = msg.ReadByte(); + ushort submarineID = msg.ReadUInt16(); if (User != null) { Shoot(User, simPosition, simPosition, rotation, ignoredBodies: User.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: false); + item.Submarine = Entity.FindEntityByID(submarineID) as Submarine; } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs index 5e5cc982f..a4903a351 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs @@ -57,13 +57,6 @@ namespace Barotrauma.Items.Components private readonly List particleEmitters = new List(); private readonly List particleEmitterCharges = new List(); - [Editable, Serialize("0,0,0,0", IsPropertySaveable.Yes, description: "Optional screen tint color when the item is being operated (R,G,B,A).")] - public Color HudTint - { - get; - private set; - } - [Serialize(false, IsPropertySaveable.No, description: "Should the charge of the connected batteries/supercapacitors be shown at the top of the screen when operating the item.")] public bool ShowChargeIndicator { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs index e487bb33d..7fefcda46 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs @@ -163,10 +163,22 @@ namespace Barotrauma { if (SelectedAny) { - SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List(SelectedList), true)); + if (SelectedList.Any(static t => t is Item it && it.GetComponent() is not null)) + { + GUI.AskForConfirmation(SubEditorScreen.CircuitBoxDeletionWarningHeader, SubEditorScreen.CircuitBoxDeletionWarningBody, onConfirm: Delete); + } + else + { + Delete(); + } + + void Delete() + { + SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List(SelectedList), true)); + SelectedList.ForEach(static e => { if (!e.Removed) { e.Remove(); } }); + SelectedList.Clear(); + } } - SelectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } }); - SelectedList.Clear(); } if (PlayerInput.IsCtrlDown()) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs index bf77b5ccc..d48f4c959 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs @@ -60,6 +60,7 @@ namespace Barotrauma } Sprite sprite = iconSprites[SpawnType.ToString()]; + Sprite sprite2 = null; if (spawnType == SpawnType.Human && AssignedJob?.Icon != null) { sprite = iconSprites["Path"]; @@ -67,17 +68,29 @@ namespace Barotrauma else if (ConnectedDoor != null) { sprite = iconSprites["Door"]; - if (ConnectedDoor.IsHorizontal && Ladders == null) + if (Ladders != null) { + sprite2 = iconSprites["Ladder"]; + } + else if (ConnectedDoor.IsHorizontal) + { + //connected to a hatch but not ladders, something's probably off here clr = Color.Yellow; } + if (!Submarine.RectContains(ConnectedDoor.Item.WorldRect, WorldPosition)) + { + clr = Color.Red; + } } else if (Ladders != null) { sprite = iconSprites["Ladder"]; } - sprite.Draw(spriteBatch, drawPos, clr, scale: iconSize / (float)sprite.SourceRect.Width, depth: 0.001f); - sprite.RelativeOrigin = Vector2.One * 0.5f; + + float spriteScale = iconSize / (float)sprite.SourceRect.Width; + sprite.Draw(spriteBatch, drawPos, clr, origin: sprite.size / 2, scale: spriteScale, depth: 0.001f); + sprite2?.Draw(spriteBatch, drawPos + sprite.size * spriteScale * 0.5f, clr, origin: sprite2.size / 2, scale: spriteScale, depth: 0.001f); + if (spawnType == SpawnType.Human && AssignedJob?.Icon != null) { AssignedJob.Icon.Draw(spriteBatch, drawPos, AssignedJob.UIColor, scale: iconSize / (float)AssignedJob.Icon.SourceRect.Width * 0.8f, depth: 0.0f); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EditorNode.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EditorNode.cs index c5424e4ba..d0406a244 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EditorNode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EditorNode.cs @@ -273,6 +273,11 @@ namespace Barotrauma GUIStyle.SubHeadingFont.DrawString(spriteBatch, Name, HeaderRectangle.Location.ToVector2() + (HeaderRectangle.Size.ToVector2() / 2) - (headerSize / 2), fontColor); } + public void AddConnection(NodeConnectionType connectionType) + { + Connections.Add(new EventEditorNodeConnection(this, connectionType)); + } + public virtual void AddOption() { Connections.Add(new EventEditorNodeConnection(this, NodeConnectionType.Option)); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index bbae3c7c7..1fd3ca751 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -16,6 +16,9 @@ namespace Barotrauma { class SubEditorScreen : EditorScreen { + public const string CircuitBoxDeletionWarningHeader = "Selection contains circuit boxes", + CircuitBoxDeletionWarningBody = "Are you sure you want to delete the selection? Any wiring inside circuit boxes will be lost and cannot be recovered."; + public const int MaxStructures = 2000; public const int MaxWalls = 500; public const int MaxItems = 5000; @@ -3915,18 +3918,31 @@ namespace Barotrauma new ContextMenuOption("editor.cut", isEnabled: hasTargets, onSelected: () => MapEntity.Cut(targets)), new ContextMenuOption("editor.copytoclipboard", isEnabled: hasTargets, onSelected: () => MapEntity.Copy(targets)), new ContextMenuOption("editor.paste", isEnabled: MapEntity.CopiedList.Any(), onSelected: () => MapEntity.Paste(cam.ScreenToWorld(PlayerInput.MousePosition))), - new ContextMenuOption("delete", isEnabled: hasTargets, onSelected: delegate - { - StoreCommand(new AddOrDeleteCommand(targets, true)); - foreach (var me in targets) - { - if (!me.Removed) { me.Remove(); } - } - }), + new ContextMenuOption("delete", isEnabled: hasTargets, onSelected: () => RemoveEntitiesWithPossibleWarning(targets)), new ContextMenuOption(TextManager.Get("editortip.shiftforextraoptions") + '\n' + TextManager.Get("editortip.altforruler"), isEnabled: false, onSelected: null)); } } + public static void RemoveEntitiesWithPossibleWarning(List targets) + { + if (targets.Any(static t => t is Item it && it.GetComponent() is not null)) + { + GUI.AskForConfirmation(CircuitBoxDeletionWarningHeader, CircuitBoxDeletionWarningBody, onConfirm: Delete); + return; + } + + Delete(); + + void Delete() + { + StoreCommand(new AddOrDeleteCommand(targets, true)); + foreach (var me in targets) + { + if (!me.Removed) { me.Remove(); } + } + } + } + private void MoveToLayer(string layer, List content) { layer ??= string.Empty; diff --git a/Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs b/Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs index 3b9f2241e..39f998cef 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Barotrauma.Items.Components; @@ -131,7 +132,7 @@ namespace Barotrauma { foreach (MapEntity receiver in receivers) { - if (receiver is Item it && it.ParentInventory != null) + if (receiver is Item { ParentInventory: not null } it) { PreviousInventories.Add(new InventorySlotItem(it.ParentInventory.FindIndex(it), it), it.ParentInventory); } @@ -192,14 +193,35 @@ namespace Barotrauma public override void Execute() { - DeleteUndelete(true); - ContainedItemsCommand?.ForEach(cmd => cmd.Execute()); + var items = DeleteUndelete(true); + ContainedItemsCommand?.ForEach(static cmd => cmd.Execute()); + CircuitBoxWorkaround(items); } public override void UnExecute() { - DeleteUndelete(false); - ContainedItemsCommand?.ForEach(cmd => cmd.UnExecute()); + var items = DeleteUndelete(false); + ContainedItemsCommand?.ForEach(static cmd => cmd.UnExecute()); + CircuitBoxWorkaround(items); + } + + // FIXME Temporary workaround for circuit boxes throwing console errors and breaking completely when undoing a deletion + private static void CircuitBoxWorkaround(Option> entitiesOption) + { + if (!entitiesOption.TryUnwrap(out var entities)) { return; } + + foreach (var entity in entities) + { + if (entity is not Item it) { continue; } + + if (it.GetComponent() is not null) + { + foreach (var container in it.GetComponents()) + { + container.Inventory.DeleteAllItems(); + } + } + } } public override void Cleanup() @@ -215,10 +237,10 @@ namespace Barotrauma CloneList?.Clear(); Receivers.Clear(); PreviousInventories?.Clear(); - ContainedItemsCommand?.ForEach(cmd => cmd.Cleanup()); + ContainedItemsCommand?.ForEach(static cmd => cmd.Cleanup()); } - private void DeleteUndelete(bool redo) + private Option> DeleteUndelete(bool redo) { bool wasDeleted = WasDeleted; @@ -227,13 +249,14 @@ namespace Barotrauma if (wasDeleted) { - Debug.Assert(Receivers.All(entity => entity.GetReplacementOrThis().Removed), "Tried to redo a deletion but some items were not deleted"); + Debug.Assert(Receivers.All(static entity => entity.GetReplacementOrThis().Removed), "Tried to redo a deletion but some items were not deleted"); List clones = MapEntity.Clone(CloneList); int length = Math.Min(Receivers.Count, clones.Count); for (int i = 0; i < length; i++) { - MapEntity clone = clones[i], receiver = Receivers[i]; + MapEntity clone = clones[i], + receiver = Receivers[i]; if (receiver.GetReplacementOrThis() is Item item && clone is Item cloneItem) { @@ -245,7 +268,7 @@ namespace Barotrauma { case null: continue; - case ItemContainer newContainer when newContainer.Inventory != null && ic is ItemContainer itemContainer && itemContainer.Inventory != null: + case ItemContainer { Inventory: not null } newContainer when ic is ItemContainer { Inventory: not null } itemContainer: itemContainer.Inventory.GetReplacementOrThiS().ReplacedBy = newContainer.Inventory; goto default; default: @@ -260,7 +283,8 @@ namespace Barotrauma for (int i = 0; i < length; i++) { - MapEntity clone = clones[i], receiver = Receivers[i]; + MapEntity clone = clones[i], + receiver = Receivers[i]; if (clone is Item it) { @@ -278,6 +302,8 @@ namespace Barotrauma { clone.Submarine = Submarine.MainSub; } + + return Option.Some(clones.ToImmutableArray()); } else { @@ -289,6 +315,8 @@ namespace Barotrauma receiver.Remove(); } } + + return Option.None; } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/ItemLabel.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/ItemLabel.cs index dbcf85e4d..81610eb59 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/ItemLabel.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/ItemLabel.cs @@ -18,6 +18,13 @@ namespace Barotrauma.Items.Components set; } + [Editable, Serialize(false, IsPropertySaveable.Yes)] + public bool IgnoreLocalization + { + get; + set; + } + [Editable, Serialize("0,0,0,255", IsPropertySaveable.Yes, description: "The color of the text displayed on the label.", alwaysUseInstanceValues: true)] public Color TextColor { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs index c1f24ccf6..00f22651c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs @@ -35,6 +35,7 @@ namespace Barotrauma.Items.Components msg.WriteSingle(launchPos.Y); msg.WriteSingle(launchRot); msg.WriteByte(eventData.SpreadCounter); + msg.WriteUInt16(LaunchSub?.ID ?? Entity.NullEntityID); } bool stuck = StickTarget != null && !item.Removed && !StickTargetRemoved(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs index 40be336b8..5d1aa4a61 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs @@ -154,7 +154,8 @@ namespace Barotrauma } var order = new Order(orderPrefab, autonomousObjective.Option, item ?? character.CurrentHull as Entity, orderPrefab.GetTargetItemComponent(item), orderGiver: character); if (order == null) { continue; } - if ((order.IgnoreAtOutpost || autonomousObjective.IgnoreAtOutpost) && Level.IsLoadedFriendlyOutpost && character.TeamID != CharacterTeamType.FriendlyNPC) + if ((order.IgnoreAtOutpost || autonomousObjective.IgnoreAtOutpost) && + Level.IsLoadedFriendlyOutpost && character.TeamID != CharacterTeamType.FriendlyNPC && !character.IsFriendlyNPCTurnedHostile) { if (Submarine.MainSub != null && Submarine.MainSub.DockedTo.None(s => s.TeamID != CharacterTeamType.FriendlyNPC && s.TeamID != character.TeamID)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index af66e1865..552fe6a3f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -1188,6 +1188,33 @@ namespace Barotrauma throw new Exception("crash command issued"); })); + commands.Add(new Command("listeditableproperties", "", (string[] args) => + { + StringBuilder sb = new StringBuilder(); + string filename; +#if CLIENT + filename = "ItemComponent properties (client).txt"; + sb.AppendLine("Client-side ItemComponent properties:"); +#else + filename = "ItemComponent properties (server).txt"; + sb.AppendLine("Server-side ItemComponent properties:"); +#endif + var itemComponents = typeof(ItemComponent).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ItemComponent))); + foreach (var ic in itemComponents.OrderBy(ic => ic.Name)) + { + sb.AppendLine(ic.Name+":"); + foreach (var prop in ic.GetProperties()) + { + if (prop.DeclaringType != ic) { continue; } + if (prop.GetCustomAttributes(inherit: false).OfType().Any()) + { + sb.AppendLine(prop.Name); + } + } + } + File.WriteAllText(filename, sb.ToString()); + })); + commands.Add(new Command("fastforward", "fastforward [seconds]: Fast forwards the game by x seconds. Note that large numbers may cause a long freeze.", (string[] args) => { float seconds = 0; @@ -1300,7 +1327,7 @@ namespace Barotrauma } #endif - commands.Add(new Command("showreputation", "showreputation: List the current reputation values.", (string[] args) => + commands.Add(new Command("showreputation", "showreputation: List the current reputation values.", (string[] args) => { if (GameMain.GameSession?.GameMode is CampaignMode campaign) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs index 5add25d3c..ef4c76774 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs @@ -132,6 +132,11 @@ namespace Barotrauma /// public readonly List AllowedLocationTypes = new List(); + /// + /// The mission can only happen in locations owned by this faction. In the mission mode, the location is forced to be owned by this faction. + /// + public readonly Identifier RequiredLocationFaction; + /// /// Show entities belonging to these sub categories when the mission starts /// @@ -198,6 +203,7 @@ namespace Barotrauma RequireWreck = element.GetAttributeBool("requirewreck", false); RequireRuin = element.GetAttributeBool("requireruin", false); BlockLocationTypeChanges = element.GetAttributeBool(nameof(BlockLocationTypeChanges), false); + RequiredLocationFaction = element.GetAttributeIdentifier(nameof(RequiredLocationFaction), Identifier.Empty); Commonness = element.GetAttributeInt("commonness", 1); AllowOtherMissionsInLevel = element.GetAttributeBool("allowothermissionsinlevel", true); if (element.GetAttribute("difficulty") != null) @@ -378,7 +384,11 @@ namespace Barotrauma { if (from == to) { - return + if (!RequiredLocationFaction.IsEmpty && from.Faction?.Prefab.Identifier != RequiredLocationFaction) + { + return false; + } + return AllowedLocationTypes.Any(lt => lt == "any") || AllowedLocationTypes.Any(lt => lt == "anyoutpost" && from.HasOutpost()) || AllowedLocationTypes.Any(lt => lt == from.Type.Identifier); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Factions.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Factions.cs index 548d30d55..d39be4e1a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Factions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Factions.cs @@ -2,7 +2,6 @@ using Microsoft.Xna.Framework; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; namespace Barotrauma { @@ -18,7 +17,7 @@ namespace Barotrauma public Reputation Reputation { get; } public FactionPrefab Prefab { get; } - public Faction(CampaignMetadata metadata, FactionPrefab prefab) + public Faction(CampaignMetadata? metadata, FactionPrefab prefab) { Prefab = prefab; Reputation = new Reputation(metadata, this, prefab.MinReputation, prefab.MaxReputation, prefab.InitialReputation); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs index 50e9ff216..1ff492a18 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs @@ -42,10 +42,10 @@ namespace Barotrauma public float Value { - get => Math.Min(MaxReputation, Metadata.GetFloat(metaDataIdentifier, InitialReputation)); + get => Metadata == null ? 0 : Math.Min(MaxReputation, Metadata.GetFloat(metaDataIdentifier, InitialReputation)); private set { - if (MathUtils.NearlyEqual(Value, value)) { return; } + if (MathUtils.NearlyEqual(Value, value) || Metadata == null) { return; } float prevValue = Value; @@ -137,7 +137,6 @@ namespace Barotrauma private Reputation(CampaignMetadata metadata, Faction faction, Location location, Identifier identifier, int minReputation, int maxReputation, int initialReputation) { - System.Diagnostics.Debug.Assert(metadata != null); System.Diagnostics.Debug.Assert(faction != null || location != null); Metadata = metadata; Identifier = identifier; diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs index 115d3dce2..5a52f982e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs @@ -388,6 +388,11 @@ namespace Barotrauma .Where(lt => missionPrefab.AllowedLocationTypes.Any(m => m == lt.Identifier)) .GetRandom(rand); dummyLocations = CreateDummyLocations(levelSeed, locationType); + if (!mission.Prefab.RequiredLocationFaction.IsEmpty && + FactionPrefab.Prefabs.TryGet(mission.Prefab.RequiredLocationFaction, out var factionPrefab)) + { + dummyLocations[0].Faction = dummyLocations[1].Faction = new Faction(metadata: null, factionPrefab); + } randomLevel = LevelData.CreateRandom(levelSeed, difficulty, levelGenerationParams, requireOutpost: true); break; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index b9146e660..2af67598e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -83,6 +83,7 @@ namespace Barotrauma.Items.Components public Attack Attack { get; private set; } private Vector2 launchPos; + public Submarine LaunchSub; private readonly HashSet hits = new HashSet(); @@ -362,6 +363,7 @@ namespace Barotrauma.Items.Components User = user; if (Item.Removed) { return; } launchPos = simPosition; + LaunchSub = item.Submarine; //set the rotation of the projectile again because dropping the projectile resets the rotation Item.SetTransform(simPosition, rotation + (Item.body.Dir * LaunchRotationRadians), findNewHull: false); if (DeactivationTime > 0) @@ -478,6 +480,7 @@ namespace Barotrauma.Items.Components Item.WaterDragCoefficient = WaterDragCoefficient; launchPos = item.SimPosition; + LaunchSub = item.Submarine; item.body.Enabled = true; if (item.body.BodyType == BodyType.Kinematic) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs index 71e414e97..0ad0227b2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs @@ -369,6 +369,13 @@ namespace Barotrauma.Items.Components [Serialize("", IsPropertySaveable.Yes, description: "[Auto Operate] Group or SpeciesName that the AI ignores when the turret is operated automatically."), Editable] public Identifier FriendlyTag { get; private set; } + [Editable, Serialize("0,0,0,0", IsPropertySaveable.Yes, description: "Optional screen tint color when the item is being operated (R,G,B,A).")] + public Color HudTint + { + get; + private set; + } + public Turret(Item item, ContentXElement element) : base(item, element) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index 27e58824a..dd3abc0ad 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -1129,7 +1129,11 @@ namespace Barotrauma var preferredContainer = new PreferredContainer(subElement); if (preferredContainer.Primary.Count == 0 && preferredContainer.Secondary.Count == 0) { - DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\": preferred container has no preferences defined ({subElement})."); + //it's ok for variants to clear the primary and secondary containers to disable the PreferredContainer element + if (variantOf == null) + { + DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\": preferred container has no preferences defined ({subElement})."); + } } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs index dce56e175..db32a7ec5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs @@ -173,6 +173,8 @@ namespace Barotrauma public readonly HashSet IgnoredSubmarines = new HashSet(); + public readonly HashSet IgnoredCharacters = new HashSet(); + /// /// Strength of the EMP effect created by the explosion. /// @@ -437,6 +439,8 @@ namespace Barotrauma foreach (Character c in Character.CharacterList) { + if (IgnoredCharacters.Contains(c)) { continue; } + if (!c.Enabled || Math.Abs(c.WorldPosition.X - worldPosition.X) > broadRange || Math.Abs(c.WorldPosition.Y - worldPosition.Y) > broadRange) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs index 5c0da41f4..ba0a62262 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs @@ -490,8 +490,8 @@ namespace Barotrauma foreach (var moduleCount in generationParams.ModuleCounts) { if (!moduleCount.RequiredFaction.IsEmpty && - location.Faction?.Prefab.Identifier != moduleCount.RequiredFaction && - location.SecondaryFaction?.Prefab.Identifier != moduleCount.RequiredFaction) + location?.Faction?.Prefab.Identifier != moduleCount.RequiredFaction && + location?.SecondaryFaction?.Prefab.Identifier != moduleCount.RequiredFaction) { continue; }