diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs index 5d2358563..8ee874c7d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs @@ -842,7 +842,7 @@ namespace Barotrauma ContentXElement headElement = info.Ragdoll.MainElement.Elements().FirstOrDefault(e => e.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)); ContentXElement headSpriteElement = headElement.GetChildElement("sprite"); - string spritePathWithTags = headSpriteElement.Attribute("texture").Value; + ContentPath spritePathWithTags = headSpriteElement.GetAttributeContentPath("texture"); var characterConfigElement = info.CharacterConfigElement; @@ -853,7 +853,7 @@ namespace Barotrauma itemsInRow = 0; foreach (var head in heads.Where(h => h.TagSet.Contains(selectedCategory))) { - string spritePath = info.Prefab.ReplaceVars(spritePathWithTags, head); + string spritePath = info.Prefab.ReplaceVars(spritePathWithTags.Value, head); if (!File.Exists(spritePath)) { continue; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs index 6c530a3a7..ed32a00b9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs @@ -521,7 +521,7 @@ namespace Barotrauma new GUITextBlock(new RectTransform(Vector2.One, healthLayout.RectTransform), string.Empty, textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont) { - TextGetter = () => $"{(int)(info.Character?.HealthPercentage ?? 100f)}%", + TextGetter = () => TextManager.GetWithVariable("percentageformat", "[value]", $"{(int)(info.Character?.HealthPercentage ?? 100f)}"), TextColor = GUIStyle.Green }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index c31514929..201d8d242 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -850,7 +850,7 @@ namespace Barotrauma GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform)); GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true); GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft); - GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), $"{Mission.GetRewardShare(targetWallet.RewardDistribution, salaryCrew, Option.None()).Percentage}%", textAlignment: Alignment.BottomRight); + GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage()), textAlignment: Alignment.BottomRight); GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center); GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f) { @@ -860,7 +860,7 @@ namespace Barotrauma BarSize = 0.1f, OnMoved = (bar, scroll) => { - rewardBlock.Text = $"{Mission.GetRewardShare((int)(scroll * 100f), salaryCrew, Option.None()).Percentage}%"; + rewardBlock.Text = TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage()); return true; }, OnReleased = (bar, scroll) => @@ -1090,10 +1090,7 @@ namespace Barotrauma GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable); } - static int GetRewardDistributionPercentage(int distribution, ImmutableArray crew) - { - return Mission.GetRewardShare(distribution, crew, Option.None()).Percentage; - } + string GetSharePercentage() => Mission.GetRewardShare(targetWallet.RewardDistribution, salaryCrew, Option.None()).Percentage.ToString(); } private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs index 81e700dc4..3c9ac933b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs @@ -184,7 +184,7 @@ namespace Barotrauma } // Exchange money Location.StoreCurrentBalance -= itemValue; - campaign.Wallet.TryDeduct(itemValue); + campaign.Bank.Give(itemValue); GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value); // Remove from the sell crate diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs index 7f8e0c43f..ffa578204 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs @@ -125,6 +125,7 @@ namespace Barotrauma InitUI(); + //backwards compatibility for saves made prior to the addition of personal wallets int oldMoney = element.GetAttributeInt("money", 0); if (oldMoney > 0) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs index a25c7787f..2770fc3c0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs @@ -315,9 +315,8 @@ namespace Barotrauma int reward = displayedMission.GetReward(Submarine.MainSub); if (selectedMissions.Contains(displayedMission) && displayedMission.Completed && reward > 0) { - LocalizedString rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", reward)); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(displayedMission.GetMissionRewardText(Submarine.MainSub))); - if (Character.Controlled is { } controlled) + if (GameMain.IsMultiplayer && Character.Controlled is { } controlled) { var (share, percentage) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, Mission.GetSalaryEligibleCrew(), Option.Some(reward)); if (share > 0) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Submarine.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Submarine.cs index b6968b44f..8f48882e1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Submarine.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Submarine.cs @@ -677,7 +677,7 @@ namespace Barotrauma if (item.ParentInventory == null) { continue; } disabledItemLightCount += item.GetComponents().Count(); } - return GameMain.LightManager.Lights.Count(l => l.CastShadows) - disabledItemLightCount; + return GameMain.LightManager.Lights.Count(l => l.CastShadows && !l.IsBackground) - disabledItemLightCount; } public void ClientReadPosition(IReadMessage msg, float sendingTime) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index 4083f49cb..559fe77b3 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -666,8 +666,11 @@ namespace Barotrauma.Networking if (ChildServerRelay.Process?.HasExited ?? true) { Disconnect(); - var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage); - msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu; + if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox).Text.Text == ChildServerRelay.CrashMessage)) + { + var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage); + msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu; + } } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index 3f382e8f7..56032d102 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -243,9 +243,8 @@ namespace Barotrauma.CharacterEditor character.AnimController.ForceSelectAnimationType = AnimationType.NotDefined; } - public override void Deselect() + protected override void DeselectEditorSpecific() { - base.Deselect(); SoundPlayer.OverrideMusicType = Identifier.Empty; GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameSettings.CurrentConfig.Audio.SoundVolume, 0); GUI.ForceMouseOn(null); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/EditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/EditorScreen.cs index 9b68e1dbe..be295b3ed 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/EditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/EditorScreen.cs @@ -7,6 +7,18 @@ namespace Barotrauma public static Color BackgroundColor = GameSettings.CurrentConfig.SubEditorBackground; public override bool IsEditor => true; + public override sealed void Deselect() + { + DeselectEditorSpecific(); + //reset cheats the player might have used in the editor + GameMain.LightManager.LightingEnabled = true; + GameMain.LightManager.LosEnabled = true; + Hull.EditFire = false; + Hull.EditWater = false; + } + + protected virtual void DeselectEditorSpecific() { } + public void CreateBackgroundColorPicker() { var msgBox = new GUIMessageBox(TextManager.Get("CharacterEditor.EditBackgroundColor"), "", new[] { TextManager.Get("Reset"), TextManager.Get("OK")}, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175)); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs index 890a4b1ce..395391803 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs @@ -519,11 +519,6 @@ namespace Barotrauma base.Select(); } - public override void Deselect() - { - base.Deselect(); - } - public override void AddToGUIUpdateList() { GuiFrame.AddToGUIUpdateList(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs index 71bc8cab5..470977caf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs @@ -289,9 +289,8 @@ namespace Barotrauma UpdateLevelObjectsList(); } - public override void Deselect() + protected override void DeselectEditorSpecific() { - base.Deselect(); pointerLightSource?.Remove(); pointerLightSource = null; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs index 418ee66ed..81473f6d6 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs @@ -153,9 +153,8 @@ namespace Barotrauma RefreshPrefabList(); } - public override void Deselect() + protected override void DeselectEditorSpecific() { - base.Deselect(); GameMain.ParticleManager.Camera = GameMain.GameScreen.Cam; filterBox.Text = ""; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SpriteEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SpriteEditorScreen.cs index f2d230caf..7e5b5e6ae 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SpriteEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SpriteEditorScreen.cs @@ -850,9 +850,8 @@ namespace Barotrauma spriteList.Select(0, autoScroll: false); } - public override void Deselect() + protected override void DeselectEditorSpecific() { - base.Deselect(); loadedSprites.ForEach(s => s.Remove()); loadedSprites.Clear(); ResetWidgets(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index 14d7493a5..2e55fe64b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -22,7 +22,7 @@ namespace Barotrauma public const int MaxStructures = 2000; public const int MaxWalls = 500; public const int MaxItems = 5000; - public const int MaxLights = 300; + public const int MaxLights = 600; public const int MaxShadowCastingLights = 60; private static Submarine MainSub @@ -852,7 +852,7 @@ namespace Barotrauma lightCount += item.GetComponents().Count(); } lightCountText.TextColor = lightCount > MaxLights ? GUIStyle.Red : Color.Lerp(GUIStyle.Green, GUIStyle.Orange, lightCount / (float)MaxLights); - return lightCount.ToString(); + return lightCount.ToString() + "/" + MaxLights; }; var shadowCastingLightCountLabel = new GUITextBlock(new RectTransform(new Vector2(0.75f, 0.0f), paddedEntityCountPanel.RectTransform), TextManager.Get("SubEditorShadowCastingLights"), textAlignment: Alignment.CenterLeft, font: GUIStyle.SmallFont, wrap: true); @@ -863,10 +863,10 @@ namespace Barotrauma foreach (Item item in Item.ItemList) { if (item.ParentInventory != null) { continue; } - lightCount += item.GetComponents().Count(l => l.CastShadows); + lightCount += item.GetComponents().Count(l => l.CastShadows && !l.DrawBehindSubs); } shadowCastingLightCountText.TextColor = lightCount > MaxShadowCastingLights ? GUIStyle.Red : Color.Lerp(GUIStyle.Green, GUIStyle.Orange, lightCount / (float)MaxShadowCastingLights); - return lightCount.ToString(); + return lightCount.ToString() + "/" + MaxShadowCastingLights; }; entityCountPanel.RectTransform.NonScaledSize = new Point( @@ -1508,10 +1508,8 @@ namespace Barotrauma yield return CoroutineStatus.Success; } - public override void Deselect() + protected override void DeselectEditorSpecific() { - base.Deselect(); - CloseItem(); autoSaveLabel?.Parent?.RemoveChild(autoSaveLabel); diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 5b77eb340..80a620bcc 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 48d9ebdc3..20a82c153 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 7ee9ab78d..35a96ffc0 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index b77b4c435..c599af014 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index d22aef776..036a8d02c 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index ecbbeb3e3..989383c24 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.1.0 + 0.17.2.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs index 4dae997fb..8a2f1ef0e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -162,7 +162,9 @@ namespace Barotrauma CloseEnough = reach, DialogueIdentifier = Leak.FlowTargetHull != null ? "dialogcannotreachleak".ToIdentifier() : Identifier.Empty, TargetName = Leak.FlowTargetHull?.DisplayName, - requiredCondition = () => Leak.Submarine == character.Submarine, + requiredCondition = () => + Leak.Submarine == character.Submarine && + (Leak.FlowTargetHull != null && character.CurrentHull == Leak.FlowTargetHull || character.CanSeeTarget(Leak)), // The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue) SpeakCannotReachCondition = () => !CheckObjectiveSpecific() }, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index 4142ba190..f2bc10d8b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -21,13 +21,25 @@ namespace Barotrauma public CharacterInfoPrefab(ContentXElement headsElement, XElement varsElement, XElement menuCategoryElement, XElement pronounsElement) { Heads = headsElement.Elements().Select(e => new CharacterInfo.HeadPreset(this, e)).ToImmutableArray(); - VarTags = varsElement.Elements() - .Select(e => - (e.GetAttributeIdentifier("var", ""), - e.GetAttributeIdentifierArray("tags", Array.Empty()).ToImmutableHashSet())) - .ToImmutableDictionary(); - MenuCategoryVar = menuCategoryElement.GetAttributeIdentifier("var", Identifier.Empty); - Pronouns = pronounsElement.GetAttributeIdentifier("vars", Identifier.Empty); + if (varsElement != null) + { + VarTags = varsElement.Elements() + .Select(e => + (e.GetAttributeIdentifier("var", ""), + e.GetAttributeIdentifierArray("tags", Array.Empty()).ToImmutableHashSet())) + .ToImmutableDictionary(); + } + else + { + VarTags = new[] + { + ("GENDER".ToIdentifier(), + new[] { "female".ToIdentifier(), "male".ToIdentifier() }.ToImmutableHashSet()) + }.ToImmutableDictionary(); + } + + MenuCategoryVar = menuCategoryElement?.GetAttributeIdentifier("var", Identifier.Empty) ?? "GENDER".ToIdentifier(); + Pronouns = pronounsElement?.GetAttributeIdentifier("vars", Identifier.Empty) ?? "GENDER".ToIdentifier(); } public string ReplaceVars(string str, CharacterInfo.HeadPreset headPreset) { @@ -135,7 +147,13 @@ namespace Barotrauma public string Tags { get { return string.Join(",", TagSet); } - private set { TagSet = value.Split(",").Select(s => s.ToIdentifier()).ToImmutableHashSet(); } + private set + { + TagSet = value.Split(",") + .Select(s => s.ToIdentifier()) + .Where(id => !id.IsEmpty) + .ToImmutableHashSet(); + } } [Serialize("0,0", IsPropertySaveable.No)] @@ -149,6 +167,20 @@ namespace Barotrauma { characterInfoPrefab = charInfoPrefab; SerializableProperties = SerializableProperty.DeserializeProperties(this, element); + DetermineTagsFromLegacyFormat(element); + } + + private void DetermineTagsFromLegacyFormat(XElement element) + { + void addTag(string tag) + => TagSet = TagSet.Add(tag.ToIdentifier()); + + string headId = element.GetAttributeString("id", ""); + string gender = element.GetAttributeString("gender", ""); + string race = element.GetAttributeString("race", ""); + if (!headId.IsNullOrEmpty()) { addTag($"head{headId}"); } + if (!gender.IsNullOrEmpty()) { addTag(gender); } + if (!race.IsNullOrEmpty()) { addTag(race); } } } @@ -438,12 +470,37 @@ namespace Barotrauma public readonly ImmutableArray<(Color Color, float Commonness)> FacialHairColors; public readonly ImmutableArray<(Color Color, float Commonness)> SkinColors; - private void GetName(ContentPath namesFile, Rand.RandSync randSync, out string name) + private void GetName(Rand.RandSync randSync, out string name) { - XDocument doc = XMLExtensions.TryLoadXml(namesFile); - name = doc.Root.GetAttributeString("format", ""); + var nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name"); + ContentPath namesXmlFile = nameElement?.GetAttributeContentPath("path") ?? ContentPath.Empty; + XElement namesXml = null; + if (!namesXmlFile.IsNullOrEmpty()) //names.xml is defined + { + XDocument doc = XMLExtensions.TryLoadXml(namesXmlFile); + namesXml = doc.Root; + } + else //the legacy firstnames.txt/lastnames.txt shit is defined + { + namesXml = new XElement("names", new XAttribute("format", "[firstname] [lastname]")); + var firstNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? ""); + var lastNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? ""); + if (File.Exists(firstNamesPath) && File.Exists(lastNamesPath)) + { + var firstNames = File.ReadAllLines(firstNamesPath); + var lastNames = File.ReadAllLines(lastNamesPath); + namesXml.Add(firstNames.Select(n => new XElement("firstname", new XAttribute("value", n)))); + namesXml.Add(lastNames.Select(n => new XElement("lastname", new XAttribute("value", n)))); + } + else //the files don't exist, just fall back to the vanilla names + { + XDocument doc = XMLExtensions.TryLoadXml("Content/Characters/Human/names.xml"); + namesXml = doc.Root; + } + } + name = namesXml.GetAttributeString("format", ""); Dictionary> entries = new Dictionary>(); - foreach (var subElement in doc.Root.Elements()) + foreach (var subElement in namesXml.Elements()) { Identifier elemName = subElement.NameAsIdentifier(); if (!entries.ContainsKey(elemName)) @@ -477,8 +534,21 @@ namespace Barotrauma // talent-relevant values public int MissionsCompletedSinceDeath = 0; + private static bool ElementHasSpecifierTags(XElement element) + => element.GetAttributeBool("specifiertags", + element.GetAttributeBool("genders", + element.GetAttributeBool("races", false))); + // Used for creating the data - public CharacterInfo(Identifier speciesName, string name = "", string originalName = "", Either jobOrJobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced, Identifier npcIdentifier = default) + public CharacterInfo( + Identifier speciesName, + string name = "", + string originalName = "", + Either jobOrJobPrefab = null, + string ragdollFileName = null, + int variant = 0, + Rand.RandSync randSync = Rand.RandSync.Unsynced, + Identifier npcIdentifier = default) { JobPrefab jobPrefab = null; Job job = null; @@ -494,7 +564,7 @@ namespace Barotrauma CharacterConfigElement = CharacterPrefab.FindBySpeciesName(SpeciesName)?.ConfigElement; if (CharacterConfigElement == null) { return; } // TODO: support for variants - HasSpecifierTags = CharacterConfigElement.GetAttributeBool("specifiertags", false); + HasSpecifierTags = ElementHasSpecifierTags(CharacterConfigElement); if (HasSpecifierTags) { HairColors = CharacterConfigElement.GetAttributeTupleArray("haircolors", new (Color, float)[] { (Color.WhiteSmoke, 100f) }).ToImmutableArray(); @@ -537,12 +607,7 @@ namespace Barotrauma public string GetRandomName(Rand.RandSync randSync) { - string name = ""; - var nameElement = CharacterConfigElement.GetChildElement("names"); - if (nameElement != null) - { - GetName(nameElement.GetAttributeContentPath("path") ?? ContentPath.Empty, randSync, out name); - } + GetName(randSync, out string name); return name; } @@ -623,7 +688,7 @@ namespace Barotrauma if (element == null) { return; } // TODO: support for variants CharacterConfigElement = element; - HasSpecifierTags = CharacterConfigElement.GetAttributeBool("specifiertags", false); + HasSpecifierTags = ElementHasSpecifierTags(CharacterConfigElement); if (HasSpecifierTags) { RecreateHead( @@ -647,7 +712,7 @@ namespace Barotrauma var nameElement = CharacterConfigElement.GetChildElement("names"); if (nameElement != null) { - GetName(nameElement.GetAttributeContentPath("path") ?? ContentPath.Empty, Rand.RandSync.ServerAndClient, out Name); + GetName(Rand.RandSync.ServerAndClient, out Name); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs index 6cec0f84c..f41b7720f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs @@ -36,7 +36,7 @@ namespace Barotrauma var menuCategoryElement = ConfigElement.GetChildElement("MenuCategory"); var pronounsElement = ConfigElement.GetChildElement("Pronouns"); - if (headsElement != null && varsElement != null && menuCategoryElement != null && pronounsElement != null) + if (headsElement != null) { CharacterInfoPrefab = new CharacterInfoPrefab(headsElement, varsElement, menuCategoryElement, pronounsElement); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 68d156778..640bf791c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -380,20 +380,24 @@ namespace Barotrauma public string Tags { get { return string.Join(',', TagSet); } - private set { TagSet = value.Split(',').ToIdentifiers().ToImmutableHashSet(); } + private set + { + TagSet = value.Split(',') + .ToIdentifiers() + .Where(id => !id.IsEmpty) + .ToImmutableHashSet(); + } } public ImmutableHashSet TagSet { get; private set; } public SoundParams(ContentXElement element, CharacterParams character) : base(element, character) { - HashSet tags = TagSet.ToHashSet(); Identifier genderFallback = element.GetAttributeIdentifier("gender", ""); if (genderFallback != Identifier.Empty && genderFallback != "None") { - tags.Add(genderFallback); + TagSet = TagSet.Add(genderFallback); } - TagSet = tags.ToImmutableHashSet(); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs index 40c00e220..a525764bd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs @@ -446,7 +446,7 @@ namespace Barotrauma #elif CLIENT return characters; #endif - static bool IsAlive(Character c) { return c.Info != null && !c.IsDead; } + static bool IsAlive(Character c) { return c?.Info != null && !c.IsDead; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs index 3cedefab8..cb24eb337 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs @@ -58,7 +58,7 @@ namespace Barotrauma IsEquipped = new bool[capacity]; SlotTypes = new InvSlotType[capacity]; - AccessibleWhenAlive = element.GetAttributeBool("accessiblewhenalive", false); + AccessibleWhenAlive = element.GetAttributeBool("accessiblewhenalive", character.Info != null); AccessibleByOwner = element.GetAttributeBool("accessiblebyowner", AccessibleWhenAlive); string[] slotTypeNames = ParseSlotTypes(element); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs index 7a2cb168d..03c061552 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs @@ -370,7 +370,7 @@ namespace Barotrauma.Items.Components public Item GetFocusTarget() { - var positionOut = item.Connections.Find(c => c.Name == "position_out"); + var positionOut = item.Connections?.Find(c => c.Name == "position_out"); if (positionOut == null) { return null; } item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), positionOut); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs index ef5d693af..529490ecc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs @@ -57,7 +57,7 @@ namespace Barotrauma.Items.Components } [Editable, Serialize(true, IsPropertySaveable.Yes, description: "Should structures cast shadows when light from this light source hits them. " + - "Disabling shadows increases the performance of the game, and is recommended for lights with a short range.", alwaysUseInstanceValues: true)] + "Disabling shadows increases the performance of the game, and is recommended for lights with a short range. Lights that are set to be drawn behind subs don't cast shadows, regardless of this setting.", alwaysUseInstanceValues: true)] public bool CastShadows { get { return castShadows; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index cd5e684d5..42b982c38 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -407,8 +407,6 @@ namespace Barotrauma Loaded = this; Generating = true; - Rand.Tracker.Reset(); - Rand.Tracker.Active = true; EqualityCheckValues.Clear(); EntitiesBeforeGenerate = GetEntities().ToList(); EntityCountBeforeGenerate = EntitiesBeforeGenerate.Count(); @@ -1305,8 +1303,6 @@ namespace Barotrauma //assign an ID to make entity events work //ID = FindFreeID(); Generating = false; - Rand.Tracker.Active = false; - File.WriteAllLines(GameMain.NetworkMember is { IsServer: true } ? "serverrng.txt" : "clientrng.txt", Rand.Tracker.LogMsgs); } private List GeneratePathNodes(Point startPosition, Point endPosition, Rectangle pathBorders, Tunnel parentTunnel, float variance) @@ -2443,7 +2439,6 @@ namespace Barotrauma fixedResources.Add((itemPrefab, fixedQuantityResourceInfo)); } } - levelResources.Sort((x, y) => x.commonness.CompareTo(y.commonness)); DebugConsole.Log("Generating level resources..."); var allValidLocations = GetAllValidClusterLocations(); @@ -2473,29 +2468,33 @@ namespace Barotrauma //place some of the least common resources in the abyss AbyssResources.Clear(); - for (int j = 0; j < levelResources.Count && j < 5; j++) - { - for (int i = 0; i < 10; i++) - { - var (itemPrefab, commonness) = levelResources[j]; - var location = allValidLocations.GetRandom(l => - { - if (l.Cell == null || l.Edge == null) { return false; } - if (l.EdgeCenter.Y > AbyssArea.Bottom) { return false; } - l.InitializeResources(); - return l.Resources.Count <= GetMaxResourcesOnEdge(itemPrefab, l, out _); - }, randSync: Rand.RandSync.ServerAndClient); - if (location.Cell == null || location.Edge == null) { break; } - int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.ServerAndClient); - PlaceResources(itemPrefab, clusterSize, location, out var abyssResources); - var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true); - abyssClusterLocation.Resources.AddRange(abyssResources); - AbyssResources.Add(abyssClusterLocation); - var locationIndex = allValidLocations.FindIndex(l => l.Equals(location)); - allValidLocations.RemoveAt(locationIndex); - } - } + int abyssClusterCount = (int)MathHelper.Lerp(GenerationParams.AbyssResourceClustersMin, GenerationParams.AbyssResourceClustersMax, Difficulty / 100.0f); + + for (int i = 0; i < abyssClusterCount; i++) + { + //use inverse commonness to select the abyss resources (the rarest ones are the most common in the abyss) + var selectedPrefab = ToolBox.SelectWeightedRandom( + levelResources.Select(it => it.itemPrefab).ToList(), + levelResources.Select(it => it.commonness <= 0.0f ? 0.0f : 1.0f / it.commonness).ToList(), + Rand.RandSync.ServerAndClient); + var location = allValidLocations.GetRandom(l => + { + if (l.Cell == null || l.Edge == null) { return false; } + if (l.EdgeCenter.Y > AbyssArea.Bottom) { return false; } + l.InitializeResources(); + return l.Resources.Count <= GetMaxResourcesOnEdge(selectedPrefab, l, out _); + }, randSync: Rand.RandSync.ServerAndClient); + + if (location.Cell == null || location.Edge == null) { break; } + int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.ServerAndClient); + PlaceResources(selectedPrefab, clusterSize, location, out var abyssResources); + var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true); + abyssClusterLocation.Resources.AddRange(abyssResources); + AbyssResources.Add(abyssClusterLocation); + var locationIndex = allValidLocations.FindIndex(l => l.Equals(location)); + allValidLocations.RemoveAt(locationIndex); + } PathPoints.Clear(); nextPathPointId = 0; @@ -2603,7 +2602,14 @@ namespace Barotrauma #if DEBUG DebugConsole.NewMessage("Level resources spawned: " + itemCount + "\n" + - "Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count); + " Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count + "\n" + + " Total value: "+ PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)))+" mk"); + if (AbyssResources.Count > 0) + { + + DebugConsole.NewMessage("Abyss resources spawned: " + AbyssResources.Sum(a => a.Resources.Count) + "\n" + + " Total value: " + AbyssResources.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)) + " mk"); + } #endif DebugConsole.Log("Level resources generated"); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelGenerationParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelGenerationParams.cs index 3ee01232f..d1fc85553 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelGenerationParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelGenerationParams.cs @@ -387,6 +387,20 @@ namespace Barotrauma set; } + [Serialize(3, IsPropertySaveable.Yes, description: "Minimum number of resource clusters in the abyss (the actual number is picked between min and max according to the level difficulty)"), Editable(MinValueInt = 0, MaxValueInt = 1000)] + public int AbyssResourceClustersMin + { + get; + set; + } + + [Serialize(20, IsPropertySaveable.Yes, description: "Maximum number of resource clusters in the abyss (the actual number is picked between min and max according to the level difficulty)"), Editable(MinValueInt = 0, MaxValueInt = 1000)] + public int AbyssResourceClustersMax + { + get; + set; + } + [Serialize(-300000, IsPropertySaveable.Yes, description: "How far below the level the sea floor is placed."), Editable(MinValueFloat = Level.MaxEntityDepth, MaxValueFloat = 0.0f)] public int SeaFloorDepth { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/Rand.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/Rand.cs index 55be14eb5..3e739b555 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/Rand.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/Rand.cs @@ -11,38 +11,6 @@ namespace Barotrauma { public static class Rand { - [Obsolete("TODO: remove")] - public static class Tracker - { - private readonly static List logMsgs = new List(); - public static IReadOnlyList LogMsgs => logMsgs; - - public static bool Active = false; - - public static void Reset() - { - logMsgs.Clear(); - Active = false; - } - - public static void RegisterCall(int stDepth=4) - { - if (!Active) { return; } - var st = new StackTrace(skipFrames: 2, fNeedFileInfo: true); - var frames = st.GetFrames(); - string msg = string.Join("; ", - frames.Take(stDepth).Select(f => - $"{Path.GetFileNameWithoutExtension(f.GetFileName())}:{f.GetFileLineNumber()}")); - logMsgs.Add(msg); - } - - public static void Log(string msg) - { - if (!Active) { return; } - logMsgs.Add(msg); - } - } - public enum RandSync { Unsynced, //not synced, used for unimportant details like minor particle properties @@ -81,8 +49,6 @@ namespace Barotrauma public static int ThreadId = 0; private static void CheckRandThreadSafety(RandSync sync) { - if (sync == RandSync.ServerAndClient) { Tracker.RegisterCall(); } - if (ThreadId != 0 && sync == RandSync.Unsynced) { if (System.Threading.Thread.CurrentThread.ManagedThreadId != ThreadId) diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index a24e889aa..f5663e4fd 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,24 @@ +--------------------------------------------------------------------------------------------------------- +v0.17.2.0 +--------------------------------------------------------------------------------------------------------- + +Changes: +- Adjusted abyss resource spawning: less resources per level, the number of resources is relative to the difficulty, the spawned resources aren't guaranteed to always be the 5 least common alien materials. +- Increased maximum number of lights from 300 to 600 (unstable only). +- Backwards compatibility with human mods made before modding refactor (unstable only). + +Fixes: +- Fixed server crash in GetSalaryEligibleCrew (unstable only). +- Fixed crashing in Controller.GetFocusTarget (unstable only). +- Fixed "Tried to access crew wallets in singleplayer" error at the end of the round (unstable only). +- Fixed selling items taking money instead of giving it (unstable only). +- Fixed lights that are drawn behind subs counting as shadow-casting in the sub editor. +- Fixed server host creating 2 disconnect message boxes if the server crashes. +- Deactivate certain cheats when leaving an editor. Fixes ability to use certain cheat commands in an editor (which is now allowed without having to enable cheats) and then switch back to the game (unstable only). + +AI: +- Fixed bots sometimes getting stuck to doors when they are trying to fix a hull behind it. Happened because the goto objective was completed before the bot could open the door. + --------------------------------------------------------------------------------------------------------- v0.17.1.0 ---------------------------------------------------------------------------------------------------------