From c8657caefa5c6928013a5152ac0ad301d99b405c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Feb 2026 19:56:19 +0200 Subject: [PATCH 1/2] Update .NET SDK version from 6 to 8 in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5725f01d9..b1aa385e2 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,6 @@ If you're interested in working on the code, either to develop mods or to contri ### Windows - [Visual Studio](https://www.visualstudio.com/vs/community/) with C# 10 support (VS 2022 or later recommended) ### Linux -- [.NET 6 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux) +- [.NET 8 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux) ### macOS - [Visual Studio 2022 for Mac](https://visualstudio.microsoft.com/vs/mac/) From a4607dffad34c056783e057228e75fc22e3127f6 Mon Sep 17 00:00:00 2001 From: Regalis11 Date: Thu, 9 Apr 2026 15:10:07 +0300 Subject: [PATCH 2/2] v1.12.6.2 (Spring Update 2026) --- .../Characters/AI/EnemyAIController.cs | 9 +- .../Characters/AI/HumanAIController.cs | 16 +- .../Characters/Animation/Ragdoll.cs | 8 +- .../ClientSource/Characters/Character.cs | 4 +- .../Characters/InteractionLabelManager.cs | 16 +- .../ClientSource/Characters/Limb.cs | 11 +- .../CircuitBox/CircuitBoxInputOutputNode.cs | 2 +- .../Events/EventActions/ConversationAction.cs | 13 +- .../Missions/AbandonedOutpostMission.cs | 12 +- .../Events/Missions/CustomMission.cs | 8 + .../Events/Missions/SalvageMission.cs | 2 +- .../ClientSource/GUI/GUIComponent.cs | 11 +- .../ClientSource/GUI/GUIDropDown.cs | 4 +- .../ClientSource/GUI/HRManagerUI.cs | 29 +- .../Items/Components/ItemComponent.cs | 16 +- .../Items/Components/ItemContainer.cs | 4 +- .../Items/Components/LightComponent.cs | 26 +- .../Items/Components/Machines/Controller.cs | 48 +- .../Items/Components/Machines/Fabricator.cs | 54 +- .../Items/Components/Machines/MiniMap.cs | 1 + .../Items/Components/Machines/Sonar.cs | 28 +- .../Items/Components/Repairable.cs | 2 +- .../Items/Components/Signal/CircuitBox.cs | 2 +- .../Components/Signal/ConnectionPanel.cs | 2 +- .../Items/Components/StatusHUD.cs | 30 +- .../ClientSource/Items/Inventory.cs | 5 +- .../ClientSource/Items/Item.cs | 46 +- .../ClientSource/Items/ItemPrefab.cs | 8 + .../BarotraumaClient/ClientSource/Map/Hull.cs | 15 +- .../ClientSource/Map/Lights/LightManager.cs | 10 +- .../ClientSource/Map/Lights/LightSource.cs | 39 +- .../ClientSource/Map/Structure.cs | 7 +- .../Primitives/Peers/LidgrenClientPeer.cs | 7 + .../ClientSource/Screens/GameScreen.cs | 2 +- .../Screens/MainMenuScreen/MainMenuScreen.cs | 37 +- .../ClientSource/Screens/ModDownloadScreen.cs | 2 +- .../ClientSource/Screens/SubEditorScreen.cs | 48 +- .../Serialization/SerializableEntityEditor.cs | 79 +- .../ClientSource/SpamServerFilter.cs | 20 +- .../ClientSource/Steam/Workshop.cs | 26 +- .../Steam/WorkshopMenu/Mutable/ItemList.cs | 4 +- .../BarotraumaClient/LinuxClient.csproj | 2 +- Barotrauma/BarotraumaClient/MacClient.csproj | 2 +- .../BarotraumaClient/WindowsClient.csproj | 2 +- .../BarotraumaServer/LinuxServer.csproj | 2 +- Barotrauma/BarotraumaServer/MacServer.csproj | 2 +- .../ServerSource/Events/EventManager.cs | 9 + .../Events/Missions/CombatMission.cs | 2 +- .../BarotraumaServer/ServerSource/GameMain.cs | 3 + .../Items/Components/Machines/Controller.cs | 2 +- .../Items/Components/Repairable.cs | 7 +- .../ServerSource/Items/Inventory.cs | 23 +- .../ServerSource/Items/Item.cs | 2 - .../BarotraumaServer/ServerSource/Map/Hull.cs | 3 +- .../ServerSource/Networking/ChatMessage.cs | 3 + .../ServerSource/Networking/KarmaManager.cs | 19 +- .../Peers/Server/LidgrenServerPeer.cs | 7 + .../ServerSource/Networking/RespawnManager.cs | 17 + .../ServerSource/Networking/ServerSettings.cs | 2 +- .../BarotraumaServer/WindowsServer.csproj | 2 +- .../Characters/Crawler/Crawler.xml | 5 + .../Lighting stress (10000 lights).sub | Bin 0 -> 382364 bytes .../filelist.xml | 4 + .../EthanolPowerGenerator.png | Bin 0 -> 45363 bytes .../OxygenDispenserTest.xml | 23 + .../RotationAndFlippingTests.sub | Bin 10094 -> 13456 bytes .../StatusEffectAndLightTest.xml | 36 + .../filelist.xml | 4 +- .../[DebugOnlyTest]TestPathFinding/Events.xml | 159 ++ .../[DebugOnlyTest]TestPathFinding.sub | Bin 0 -> 108613 bytes .../filelist.xml | 8 + Barotrauma/BarotraumaShared/README.txt | 38 - .../SharedSource/AchievementManager.cs | 11 +- .../SharedSource/Characters/AI/AITarget.cs | 8 + .../Characters/AI/EnemyAIController.cs | 225 ++- .../Characters/AI/HumanAIController.cs | 2 +- .../Characters/AI/IndoorsSteeringManager.cs | 239 ++- .../Characters/AI/Objectives/AIObjective.cs | 18 +- .../AI/Objectives/AIObjectiveCleanupItems.cs | 2 +- .../AI/Objectives/AIObjectiveCombat.cs | 18 +- .../Objectives/AIObjectiveDeconstructItem.cs | 6 +- .../Objectives/AIObjectiveDeconstructItems.cs | 6 +- .../Objectives/AIObjectiveExtinguishFire.cs | 2 +- .../Objectives/AIObjectiveExtinguishFires.cs | 2 + .../AI/Objectives/AIObjectiveGetItem.cs | 29 +- .../AI/Objectives/AIObjectiveGoTo.cs | 1 + .../AI/Objectives/AIObjectiveIdle.cs | 5 +- .../AI/Objectives/AIObjectiveInspectNoises.cs | 7 +- .../AI/Objectives/AIObjectiveLoadItems.cs | 2 +- .../AI/Objectives/AIObjectiveOperateItem.cs | 1 + .../AI/Objectives/AIObjectivePumpWater.cs | 2 +- .../AI/Objectives/AIObjectiveRescueAll.cs | 2 +- .../SharedSource/Characters/AICharacter.cs | 4 +- .../Animation/FishAnimController.cs | 2 +- .../Characters/Animation/Ragdoll.cs | 65 +- .../SharedSource/Characters/Character.cs | 173 +- .../Characters/CharacterPrefab.cs | 1 + .../Health/Afflictions/AfflictionPrefab.cs | 2 +- .../Characters/Health/CharacterHealth.cs | 16 +- .../SharedSource/Characters/HumanPrefab.cs | 2 +- .../SharedSource/Characters/Limb.cs | 2 +- .../Characters/Params/CharacterParams.cs | 4 +- .../CircuitBox/CircuitBoxInputOutputNode.cs | 2 +- .../ContentFile/CharacterFile.cs | 5 +- .../ContentPackage/ContentPackage.cs | 11 +- .../SharedSource/DebugConsole.cs | 5 +- .../SharedSource/Decals/Decal.cs | 7 +- .../BarotraumaShared/SharedSource/Enums.cs | 8 + .../SharedSource/Events/Event.cs | 6 +- .../EventActions/CheckConditionalAction.cs | 8 +- .../Events/EventActions/ConversationAction.cs | 71 +- .../Events/EventActions/CountTargetsAction.cs | 1 + .../Events/EventActions/EventAction.cs | 19 +- .../Events/EventActions/ForceSayAction.cs | 62 + .../Events/EventActions/MissionStateAction.cs | 123 +- .../Events/EventActions/NPCFollowAction.cs | 8 +- .../Events/EventActions/SpawnAction.cs | 4 + .../SharedSource/Events/EventManager.cs | 57 +- .../Missions/AbandonedOutpostMission.cs | 2 +- .../Events/Missions/BeaconMission.cs | 2 +- .../Events/Missions/CargoMission.cs | 2 +- .../Events/Missions/CombatMission.cs | 2 +- .../Events/Missions/CustomMission.cs | 18 + .../Missions/EliminateTargetsMission.cs | 4 +- .../Events/Missions/EndMission.cs | 4 +- .../Events/Missions/EscortMission.cs | 2 +- .../Events/Missions/GoToMission.cs | 4 +- .../Events/Missions/MineralMission.cs | 10 +- .../SharedSource/Events/Missions/Mission.cs | 16 +- .../Events/Missions/MissionPrefab.cs | 12 +- .../Events/Missions/MonsterMission.cs | 2 +- .../Events/Missions/NestMission.cs | 2 +- .../Events/Missions/PirateMission.cs | 2 +- .../Events/Missions/SalvageMission.cs | 2 +- .../Events/Missions/ScanMission.cs | 51 +- .../GameAnalytics/GameAnalyticsConsent.cs | 11 +- .../GameSession/GameModes/CampaignMode.cs | 2 +- .../GameSession/GameModes/MissionMode.cs | 3 +- .../SharedSource/GameSession/GameSession.cs | 31 +- .../SharedSource/Items/CharacterInventory.cs | 69 +- .../Items/Components/Holdable/Holdable.cs | 6 + .../Items/Components/Holdable/MeleeWeapon.cs | 15 +- .../Items/Components/ItemComponent.cs | 5 +- .../Items/Components/ItemContainer.cs | 32 +- .../LinkedControllerCharacterComponent.cs | 121 ++ .../Items/Components/Machines/Controller.cs | 482 +++++- .../Components/Machines/Deconstructor.cs | 152 +- .../Items/Components/Projectile.cs | 10 + .../Items/Components/Repairable.cs | 5 +- .../Items/Components/Signal/Connection.cs | 5 + .../Items/Components/Signal/LightComponent.cs | 1 + .../SharedSource/Items/Components/Turret.cs | 42 +- .../SharedSource/Items/Inventory.cs | 15 +- .../SharedSource/Items/Item.cs | 24 +- .../SharedSource/Items/ItemInventory.cs | 10 +- .../SharedSource/Items/ItemPrefab.cs | 4 + .../SharedSource/Items/RelatedItem.cs | 2 +- .../BarotraumaShared/SharedSource/Map/Hull.cs | 20 +- .../SharedSource/Map/Levels/Level.cs | 22 + .../SharedSource/Map/Levels/LevelData.cs | 3 +- .../SharedSource/Map/Structure.cs | 2 +- .../SharedSource/Map/WayPoint.cs | 6 +- .../SharedSource/Networking/NetConfig.cs | 6 + .../SharedSource/Networking/NetIdUtils.cs | 6 - .../SteamAuthTicketForEosHostAuthenticator.cs | 11 +- .../SharedSource/Networking/ServerSettings.cs | 2 +- .../SharedSource/Physics/PhysicsBody.cs | 4 +- .../SharedSource/Prefabs/PrefabCollection.cs | 2 +- .../Serialization/XMLExtensions.cs | 21 + .../SharedSource/Settings/GameSettings.cs | 12 + .../StatusEffects/StatusEffect.cs | 49 +- .../Text/LocalizedString/TrimLString.cs | 8 +- .../SharedSource/Text/TextPack.cs | 5 +- .../SharedSource/Utils/RestFactory.cs | 35 + Barotrauma/BarotraumaShared/changelog.txt | 90 + .../BarotraumaCore/BarotraumaCore.csproj | 56 +- .../BarotraumaCore/Utils/ToolBoxCore.cs | 16 +- .../EosInterface/EosInterface.csproj | 52 +- Libraries/Concentus/.gitignore | 478 +++--- .../Concentus/Concentus.NetStandard.csproj | 40 +- .../Farseer.NetStandard.csproj | 80 +- .../GA_SDK_NETSTANDARD.csproj | 70 +- .../SharpFont/SharpFont.NetStandard.csproj | 90 +- Libraries/XNATypes/XNATypes.csproj | 20 +- .../opus/win32/VS2015/common.props | 162 +- .../opus/win32/VS2015/opus.vcxproj | 796 ++++----- .../opus/win32/VS2015/opus.vcxproj.filters | 1486 ++++++++--------- .../opus/win32/VS2015/opus_demo.vcxproj | 340 ++-- .../win32/VS2015/opus_demo.vcxproj.filters | 42 +- .../opus/win32/VS2015/test_opus_api.vcxproj | 340 ++-- .../VS2015/test_opus_api.vcxproj.filters | 26 +- .../win32/VS2015/test_opus_decode.vcxproj | 340 ++-- .../VS2015/test_opus_decode.vcxproj.filters | 26 +- .../win32/VS2015/test_opus_encode.vcxproj | 342 ++-- .../VS2015/test_opus_encode.vcxproj.filters | 32 +- .../opus/win32/genversion.bat | 74 +- .../webm-mem-playback.vcxproj | 294 ++-- 197 files changed, 5586 insertions(+), 3461 deletions(-) create mode 100644 Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CustomMission.cs create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Lighting stress (10000 lights)/Lighting stress (10000 lights).sub create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Lighting stress (10000 lights)/filelist.xml create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/EthanolPowerGenerator.png create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/OxygenDispenserTest.xml create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/StatusEffectAndLightTest.xml create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/Events.xml create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/[DebugOnlyTest]TestPathFinding.sub create mode 100644 Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/filelist.xml delete mode 100644 Barotrauma/BarotraumaShared/README.txt create mode 100644 Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ForceSayAction.cs create mode 100644 Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CustomMission.cs create mode 100644 Barotrauma/BarotraumaShared/SharedSource/Items/Components/LinkedControllerCharacterComponent.cs create mode 100644 Barotrauma/BarotraumaShared/SharedSource/Utils/RestFactory.cs diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs index 49c4b4309..1e7554604 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs @@ -29,7 +29,7 @@ namespace Barotrauma } } } - else if (SelectedAiTarget?.Entity != null) + else if (SelectedAiTarget?.Entity != null && AttackLimb != null) { Vector2 targetPos = SelectedAiTarget.Entity.DrawPosition; if (State == AIState.Attack) @@ -37,15 +37,16 @@ namespace Barotrauma targetPos = attackWorldPos; } targetPos.Y = -targetPos.Y; - - GUI.DrawLine(spriteBatch, pos, targetPos, GUIStyle.Red * 0.5f, 0, 4); + Vector2 attackLimbPos = AttackLimb.DrawPosition; + attackLimbPos.Y = -attackLimbPos.Y; + GUI.DrawLine(spriteBatch, attackLimbPos, targetPos, GUIStyle.Red * 0.75f, 0, 4); if (wallTarget != null && !IsCoolDownRunning) { Vector2 wallTargetPos = wallTarget.Position; if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.DrawPosition; } wallTargetPos.Y = -wallTargetPos.Y; GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false); - GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5); + GUI.DrawLine(spriteBatch, attackLimbPos, wallTargetPos, Color.Orange * 0.75f, 0, 5); } GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity}", GUIStyle.Red, Color.Black); GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 40.0f, $"{targetValue.FormatZeroDecimal()} (M: {CurrentTargetMemory?.Priority.FormatZeroDecimal()}, P: {CurrentTargetingParams?.Priority.FormatZeroDecimal()})", GUIStyle.Red, Color.Black); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/HumanAIController.cs index 4e628af8b..9e3ac4669 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/HumanAIController.cs @@ -23,6 +23,8 @@ namespace Barotrauma //GUI.DrawString(spriteBatch, pos + textOffset, $"AI TARGET: {SelectedAiTarget.Entity.ToString()}", Color.White, Color.Black); } + Vector2 spacing = new Vector2(0, GUIStyle.Font.MeasureChar('T').Y); + Vector2 stringDrawPos = pos + textOffset; GUI.DrawString(spriteBatch, stringDrawPos, Character.Name, Color.White, Color.Black); @@ -33,14 +35,14 @@ namespace Barotrauma currentOrders.Sort((x, y) => y.ManualPriority.CompareTo(x.ManualPriority)); for (int i = 0; i < currentOrders.Count; i++) { - stringDrawPos += new Vector2(0, 20); + stringDrawPos += spacing; var order = currentOrders[i]; GUI.DrawString(spriteBatch, stringDrawPos, $"ORDER {i + 1}: {order.Objective.DebugTag} ({order.Objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black); } } else if (ObjectiveManager.WaitTimer > 0) { - stringDrawPos += new Vector2(0, 20); + stringDrawPos += spacing; GUI.DrawString(spriteBatch, stringDrawPos - textOffset, $"Waiting... {ObjectiveManager.WaitTimer.FormatZeroDecimal()}", Color.White, Color.Black); } var currentObjective = ObjectiveManager.CurrentObjective; @@ -49,19 +51,19 @@ namespace Barotrauma int offset = currentOrder != null ? 20 + ((ObjectiveManager.CurrentOrders.Count - 1) * 20) : 0; if (currentOrder == null || currentOrder.Priority <= 0) { - stringDrawPos += new Vector2(0, 20); + stringDrawPos += spacing; GUI.DrawString(spriteBatch, stringDrawPos, $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black); } var subObjective = currentObjective.CurrentSubObjective; if (subObjective != null) { - stringDrawPos += new Vector2(0, 20); + stringDrawPos += spacing; GUI.DrawString(spriteBatch, stringDrawPos, $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black); } var activeObjective = ObjectiveManager.GetActiveObjective(); if (activeObjective != null) { - stringDrawPos += new Vector2(0, 20); + stringDrawPos += spacing; GUI.DrawString(spriteBatch, stringDrawPos, $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black); } if (currentObjective is AIObjectiveCombat @@ -85,12 +87,12 @@ namespace Barotrauma } } - Vector2 objectiveStringDrawPos = stringDrawPos + new Vector2(120, 40); + Vector2 objectiveStringDrawPos = stringDrawPos + new Vector2(120, spacing.Y * 2); for (int i = 0; i < ObjectiveManager.Objectives.Count; i++) { var objective = ObjectiveManager.Objectives[i]; GUI.DrawString(spriteBatch, objectiveStringDrawPos, $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f); - objectiveStringDrawPos += new Vector2(0, 18); + objectiveStringDrawPos += spacing * 0.8f; } if (steeringManager is IndoorsSteeringManager pathSteering) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs index 6e2ac141b..ce45568d2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Animation/Ragdoll.cs @@ -547,7 +547,7 @@ namespace Barotrauma } } - public void Draw(SpriteBatch spriteBatch, Camera cam) + public void Draw(SpriteBatch spriteBatch, Camera cam, bool onlyDrawSeveredLimbs) { if (simplePhysicsEnabled) { return; } @@ -573,8 +573,12 @@ namespace Barotrauma { foreach (Limb limb in limbs) { limb.ActiveSprite.Depth += depthOffset; } } - for (int i = 0; i < limbs.Length; i++) + for (int i = 0; i < inversedLimbDrawOrder.Length; i++) { + if (onlyDrawSeveredLimbs && !inversedLimbDrawOrder[i].IsSevered) + { + continue; + } inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color); } if (!MathUtils.NearlyEqual(depthOffset, 0.0f)) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs index 0180efb8c..c38878268 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs @@ -938,8 +938,8 @@ namespace Barotrauma public void Draw(SpriteBatch spriteBatch, Camera cam) { - if (!Enabled || InvisibleTimer > 0.0f) { return; } - AnimController.Draw(spriteBatch, cam); + if (!Enabled) { return; } + AnimController.Draw(spriteBatch, cam, onlyDrawSeveredLimbs: InvisibleTimer > 0.0f); } public void DrawHUD(SpriteBatch spriteBatch, Camera cam, bool drawHealth = true) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/InteractionLabelManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/InteractionLabelManager.cs index 897637950..cd9ba6820 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/InteractionLabelManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/InteractionLabelManager.cs @@ -4,6 +4,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.Collections.Generic; using Barotrauma.Items.Components; +using System.Linq; namespace Barotrauma; @@ -106,12 +107,17 @@ public static class InteractionLabelManager } RectangleF textRect = GetLabelRect(interactableInRange, cam); - - if (labels.None(l => l.Item == interactableInRange)) + var existingLabel = labels.FirstOrDefault(l => l.Item == interactableInRange); + if (existingLabel == null) { var labelData = new LabelData(interactableInRange, textRect, RichString.Rich(interactableInRange.Prefab.Name), cam); labels.Add(labelData); } + //size of the label doesn't match - can happen when we're using a CJK font which we asynchronously render new symbols for + else if (existingLabel.TextRect.Size != textRect.Size) + { + existingLabel.TextRect = textRect; + } } PreventInteractionLabelOverlap(centerPos: character.Position); @@ -127,7 +133,11 @@ public static class InteractionLabelManager private static RectangleF GetLabelRect(Item item, Camera cam) { // create rectangle for overlap prevention - Vector2 itemTextSizeScreen = GUIStyle.SubHeadingFont.MeasureString(RichString.Rich(item.Prefab.Name).SanitizedValue) * LabelScale; + + string nameText = RichString.Rich(item.Prefab.Name).SanitizedValue; + + var font = GUIStyle.SubHeadingFont.GetFontForStr(nameText)!; + Vector2 itemTextSizeScreen = font.MeasureString(nameText) * LabelScale; Vector2 interactablePosScreen = cam.WorldToScreen(item.Position); RectangleF textRect = new RectangleF(interactablePosScreen.X, interactablePosScreen.Y, itemTextSizeScreen.X, itemTextSizeScreen.Y); // center the rectangle on the item diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs index 47e90a6cb..0d9c45be1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs @@ -340,10 +340,6 @@ namespace Barotrauma break; case "randomcolor": randomColor = subElement.GetAttributeColorArray("colors", null)?.GetRandomUnsynced(); - if (randomColor.HasValue) - { - Params.GetSprite().Color = randomColor.Value; - } break; case "lightsource": LightSource = new LightSource(subElement, GetConditionalTarget()) @@ -631,6 +627,8 @@ namespace Barotrauma SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition); } + if (character.InvisibleTimer > 0.0f) { return; } + // spawn damage particles float damageParticleAmount = damage < 1 ? 0 : Math.Min(damage / 5, 1.0f) * damageMultiplier; if (damageParticleAmount > 0.001f) @@ -734,7 +732,8 @@ namespace Barotrauma if (spriteParams == null || Alpha <= 0) { return; } float burn = spriteParams.IgnoreTint ? 0 : burnOverLayStrength; float brightness = Math.Max(1.0f - burn, 0.2f); - Color tintedColor = spriteParams.Color; + Color baseColor = randomColor ?? spriteParams.Color; + Color tintedColor = baseColor; if (!spriteParams.IgnoreTint) { tintedColor = tintedColor.Multiply(ragdoll.RagdollParams.Color); @@ -752,7 +751,7 @@ namespace Barotrauma } } Color color = new Color(tintedColor.Multiply(brightness), tintedColor.A); - Color colorWithoutTint = new Color(spriteParams.Color.Multiply(brightness), spriteParams.Color.A); + Color colorWithoutTint = new Color(baseColor.Multiply(brightness), baseColor.A); Color blankColor = new Color(brightness, brightness, brightness, 1); if (deadTimer > 0) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/CircuitBox/CircuitBoxInputOutputNode.cs b/Barotrauma/BarotraumaClient/ClientSource/CircuitBox/CircuitBoxInputOutputNode.cs index d9658086f..7e0a3b547 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/CircuitBox/CircuitBoxInputOutputNode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/CircuitBox/CircuitBoxInputOutputNode.cs @@ -31,7 +31,7 @@ namespace Barotrauma GUILayoutGroup connLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f), labelList.Content.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft); new GUITextBlock(new RectTransform(new Vector2(0.4f, 1f), connLayout.RectTransform), text: conn.Connection.DisplayName, font: GUIStyle.SubHeadingFont); - GUITextBox box = GUI.CreateTextBoxWithPlaceholder(new RectTransform(new Vector2(0.6f, 1f), connLayout.RectTransform), text: found ? labelOverride : string.Empty, conn.Connection.DisplayName.Value); + GUITextBox box = GUI.CreateTextBoxWithPlaceholder(new RectTransform(new Vector2(0.6f, 1f), connLayout.RectTransform), text: found ? labelOverride : string.Empty, conn.Connection.DefaultDisplayName.Value); box.MaxTextLength = MaxConnectionLabelLength; textBoxes.Add(conn.Name, box); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/EventActions/ConversationAction.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/EventActions/ConversationAction.cs index 3a7988c21..e7538dc03 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/EventActions/ConversationAction.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/EventActions/ConversationAction.cs @@ -277,6 +277,14 @@ namespace Barotrauma int selectedOption = (userdata as int?) ?? 0; if (actionInstance != null) { + var option = actionInstance.Options[selectedOption]; + if (GameMain.Client == null && option.ForceSay) + { + Character.Controlled.ForceSay( + option.ForceSayText.IsNullOrEmpty() ? TextManager.Get(option.Text).Fallback(option.Text) : TextManager.Get(option.ForceSayText).Fallback(option.ForceSayText), + option.ForceSayInRadio, + option.ForceSayRemoveQuotes); + } actionInstance.selectedOption = selectedOption; DisableButtons(optionButtons, btn); btn.ExternalHighlight = true; @@ -340,7 +348,8 @@ namespace Barotrauma if (speaker?.Info != null && drawChathead) { // chathead - new GUICustomComponent(new RectTransform(new Vector2(0.15f, 0.8f), content.RectTransform), onDraw: (sb, customComponent) => + int chatHeadWidth = (int)(content.RectTransform.Rect.Width * 0.15f); + new GUICustomComponent(new RectTransform(new Point(chatHeadWidth, chatHeadWidth), content.RectTransform, isFixedSize: true), onDraw: (sb, customComponent) => { speaker.Info.DrawIcon(sb, customComponent.Rect.Center.ToVector2(), customComponent.Rect.Size.ToVector2()); }); @@ -382,7 +391,7 @@ namespace Barotrauma } textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height + textContent.AbsoluteSpacing) + GUI.IntScale(16)); - content.RectTransform.MinSize = new Point(0, content.Children.Sum(c => c.Rect.Height)); + content.RectTransform.MinSize = textContent.RectTransform.MinSize; // Recalculate the text size as it is scaled up and no longer matching the text height due to the textContent's minSize increasing textBlock.CalculateHeightFromText(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs index e3a607d75..d8644061b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs @@ -61,17 +61,9 @@ namespace Barotrauma { Item.ReadSpawnData(msg); } - if (character.Submarine != null && character.AIController is EnemyAIController enemyAi) + if (character.AIController is EnemyAIController enemyAi && character.Submarine is Submarine ownSub) { - enemyAi.UnattackableSubmarines.Add(character.Submarine); - if (Submarine.MainSub != null) - { - enemyAi.UnattackableSubmarines.Add(Submarine.MainSub); - foreach (Submarine sub in Submarine.MainSub.DockedTo) - { - enemyAi.UnattackableSubmarines.Add(sub); - } - } + enemyAi.SetUnattackableSubmarines(ownSub); } } if (characters.Contains(null)) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CustomMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CustomMission.cs new file mode 100644 index 000000000..601d4ec09 --- /dev/null +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CustomMission.cs @@ -0,0 +1,8 @@ +#nullable enable +namespace Barotrauma; + +internal sealed partial class CustomMission : Mission +{ + public override bool DisplayAsCompleted => State == SuccessState; + public override bool DisplayAsFailed => State == FailureState; +} diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs index 8b9d8c492..fbf3e7a16 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs @@ -14,7 +14,7 @@ namespace Barotrauma private void TryShowRetrievedMessage() { - if (DetermineCompleted()) + if (DetermineCompleted(CampaignMode.TransitionType.None)) { HandleMessage(ref allRetrievedMessage); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs index 918b67d16..af674c696 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs @@ -1435,8 +1435,15 @@ namespace Barotrauma Uri baseAddress = new Uri(url); Uri remoteDirectory = new Uri(baseAddress, "."); string remoteFileName = Path.GetFileName(baseAddress.LocalPath); - IRestClient client = new RestClient(remoteDirectory); - var response = client.Execute(new RestRequest(remoteFileName, Method.GET)); + var client = RestFactory.CreateClient(remoteDirectory.ToString()); + var request = RestFactory.CreateRequest(remoteFileName); + var response = client.Execute(request); + if (response.ErrorException != null) + { + DebugConsole.AddWarning($"Connection error: Failed to load remote sprite from {url} " + + $"({response.ErrorException.Message})."); + return null; + } if (response.ResponseStatus != ResponseStatus.Completed) { return null; } if (response.StatusCode != HttpStatusCode.OK) { return null; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs index 3116cfd81..2b0041c13 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs @@ -26,7 +26,9 @@ namespace Barotrauma public OnSelectedHandler OnDropped; - private readonly GUIButton button; + private readonly GUIButton button; + public GUIButton Button => button; + private readonly GUIImage icon; private readonly GUIListBox listBox; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/HRManagerUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/HRManagerUI.cs index 928ae3519..ea17ff7b5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/HRManagerUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/HRManagerUI.cs @@ -710,19 +710,24 @@ namespace Barotrauma if (listBox == pendingList || listBox == crewList) { - nameBlock.RectTransform.Resize(new Point(nameBlock.Rect.Width - nameBlock.Rect.Height, nameBlock.Rect.Height)); - nameBlock.Text = ToolBox.LimitString(characterName, nameBlock.Font, nameBlock.Rect.Width); - nameBlock.RectTransform.Resize(new Point((int)(nameBlock.Padding.X + nameBlock.TextSize.X + nameBlock.Padding.Z), nameBlock.Rect.Height)); - Point size = new Point((int)(0.7f * nameBlock.Rect.Height)); - new GUIImage(new RectTransform(size, nameGroup.RectTransform), "EditIcon") { CanBeFocused = false }; - size = new Point(3 * mainGroup.AbsoluteSpacing + icon.Rect.Width + nameAndJobGroup.Rect.Width, mainGroup.Rect.Height); - new GUIButton(new RectTransform(size, frame.RectTransform) { RelativeOffset = new Vector2(0.025f) }, style: null) + //if the character is already in the crew, only check permissions - reputation doesn't matter for renaming an already-hired bot + bool canRename = listBox == crewList ? HasPermissionToHire : CanHire(characterInfo); + if (canRename) { - Enabled = CanHire(characterInfo), - ToolTip = TextManager.GetWithVariable("campaigncrew.givenicknametooltip", "[mouseprimary]", PlayerInput.PrimaryMouseLabel), - UserData = characterInfo, - OnClicked = CreateRenamingComponent - }; + nameBlock.RectTransform.Resize(new Point(nameBlock.Rect.Width - nameBlock.Rect.Height, nameBlock.Rect.Height)); + nameBlock.Text = ToolBox.LimitString(characterName, nameBlock.Font, nameBlock.Rect.Width); + nameBlock.RectTransform.Resize(new Point((int)(nameBlock.Padding.X + nameBlock.TextSize.X + nameBlock.Padding.Z), nameBlock.Rect.Height)); + Point iconSize = new Point((int)(0.7f * nameBlock.Rect.Height)); + new GUIImage(new RectTransform(iconSize, nameGroup.RectTransform), "EditIcon") { CanBeFocused = false }; + Point buttonSize = new Point(3 * mainGroup.AbsoluteSpacing + icon.Rect.Width + nameAndJobGroup.Rect.Width + (int)(iconSize.X * 1.5f), mainGroup.Rect.Height); + new GUIButton(new RectTransform(buttonSize, frame.RectTransform) { RelativeOffset = new Vector2(0.025f) }, style: null) + { + ClampMouseRectToParent = false, + ToolTip = TextManager.GetWithVariable("campaigncrew.givenicknametooltip", "[mouseprimary]", PlayerInput.PrimaryMouseLabel), + UserData = characterInfo, + OnClicked = CreateRenamingComponent + }; + } } //recalculate everything and truncate texts if needed diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs index 0452c45e7..e33660954 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs @@ -487,7 +487,21 @@ namespace Barotrauma.Items.Components return 0.0f; } - public virtual bool ShouldDrawHUD(Character character) + public bool ShouldDrawHUD(Character character) + { + if (Character.Controlled?.SelectedItem != null) + { + Controller controller = item.GetComponent(); + if (controller != null && controller.User == Character.Controlled && controller.HideAllItemComponentHUDs) + { + return false; + } + } + + return ShouldDrawHUDComponentSpecific(character); + } + + protected virtual bool ShouldDrawHUDComponentSpecific(Character character) { return true; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs index c0a6ece27..31af8751a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs @@ -552,9 +552,9 @@ namespace Barotrauma.Items.Components if (flippedY) { origin.Y = contained.Item.Sprite.SourceRect.Height - origin.Y; } float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? contained.Item.Sprite.Depth : ContainedSpriteDepth; - if (i < containedSpriteDepths.Length) + if (targetSlotIndex < containedSpriteDepths.Length) { - containedSpriteDepth = containedSpriteDepths[i]; + containedSpriteDepth = containedSpriteDepths[targetSlotIndex]; } containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/LightComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/LightComponent.cs index 4e637d1dc..82183702e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/LightComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/LightComponent.cs @@ -52,10 +52,12 @@ namespace Barotrauma.Items.Components partial void SetLightSourceTransformProjSpecific() { - Vector2 offset = Vector2.Zero; - if (LightOffset != Vector2.Zero) + Vector2 offset = LightOffset * item.Scale; + if (offset != Vector2.Zero) { - offset = Vector2.Transform(LightOffset, Matrix.CreateRotationZ(item.FlippedY ? -item.RotationRad - MathHelper.Pi : -item.RotationRad)) * item.Scale; + if (item.FlippedX) { offset.X *= -1; } + if (item.FlippedY) { offset.Y *= -1; } + offset = Vector2.Transform(offset, Matrix.CreateRotationZ(-item.RotationRad)); } if (ParentBody != null) @@ -101,7 +103,10 @@ namespace Barotrauma.Items.Components if (Light?.LightSprite == null) { return; } if ((item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled) { - Vector2 offset = Vector2.Transform(LightOffset, Matrix.CreateRotationZ(item.FlippedY ? -item.RotationRad - MathHelper.Pi : -item.RotationRad)) * item.Scale; + Vector2 offset = LightOffset * item.Scale; + if (item.FlippedX) { offset.X *= -1; } + if (item.FlippedY) { offset.Y *= -1; } + offset = Vector2.Transform(offset, Matrix.CreateRotationZ(-item.RotationRad)); Vector2 origin = Light.LightSprite.Origin; if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; } @@ -114,6 +119,7 @@ namespace Barotrauma.Items.Components { color = new Color(lightColor, Light.OverrideLightSpriteAlpha.Value); } + Light.LightSprite.Draw(spriteBatch, new Vector2(drawPos.X, -drawPos.Y), color * lightBrightness, @@ -128,8 +134,16 @@ namespace Barotrauma.Items.Components { if (Light?.LightSprite != null && item.Prefab.CanSpriteFlipX) { - Light.LightSpriteEffect = Light.LightSpriteEffect == SpriteEffects.None ? - SpriteEffects.FlipHorizontally : SpriteEffects.None; + Light.LightSpriteEffect ^= SpriteEffects.FlipHorizontally; + } + SetLightSourceTransformProjSpecific(); + } + + public override void FlipY(bool relativeToSub) + { + if (Light?.LightSprite != null && item.Prefab.CanSpriteFlipY) + { + Light.LightSpriteEffect ^= SpriteEffects.FlipVertically; } SetLightSourceTransformProjSpecific(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Controller.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Controller.cs index 710dcb9f6..bee454c79 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Controller.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Controller.cs @@ -8,6 +8,30 @@ namespace Barotrauma.Items.Components { private bool isHUDsHidden; + public void UpdateMsg() + { + if (Character.Controlled == null) { return; } + + if (!string.IsNullOrEmpty(KickOutCharacterMsg) && + SelectingKicksCharacterOut && + User != null && !User.Removed) + { + DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(KickOutCharacterMsg)); + } + else if (!string.IsNullOrEmpty(PutOtherCharacterMsg) && + AllowPuttingInOtherCharacters && + CanPutSelectedCharacter(Character.Controlled.SelectedCharacter)) + { + DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(PutOtherCharacterMsg)); + } + else + { + DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(Msg)); + } + + CharacterHUD.RecreateHudTextsIfControlling(Character.Controlled); + } + public override void DrawHUD(SpriteBatch spriteBatch, Character character) { base.DrawHUD(spriteBatch, character); @@ -69,21 +93,33 @@ namespace Barotrauma.Items.Components ushort userID = msg.ReadUInt16(); if (userID == 0) { - if (user != null) + if (User != null) { IsActive = false; - CancelUsing(user); - user = null; + CancelUsing(User); + User = null; } } else { Character newUser = Entity.FindEntityByID(userID) as Character; - if (newUser != user) + if (newUser != User) { - CancelUsing(user); + CancelUsing(User); } - user = newUser; + User = newUser; + + // If the server assigned a user to this controller but the character is not selecting the item + // on the client-side, force the selection to prevent desync. This is required for force attaching, + // since the character placed into the controller may be unconscious, and in that state + // the server no longer syncs the current SelectedItem to clients. + if (ForceUserToStayAttached && + user != null && + !user.IsAnySelectedItem(Item)) + { + user.SelectedItem = Item; + } + IsActive = true; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs index b791fcf87..5dca29d13 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs @@ -434,18 +434,13 @@ namespace Barotrauma.Items.Components foreach (FabricationRecipe fi in fabricationRecipes.Values) { - RichString recipeTooltip = - fi.RequiresRecipe ? - RichString.Rich(fi.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{TextManager.Get("fabricatorrequiresrecipe")}‖color:end‖") : - RichString.Rich(fi.TargetItem.Description); - var frame = new GUIFrame(new RectTransform(new Point(itemList.Content.Rect.Width, (int)(40 * GUI.yScale)), itemList.Content.RectTransform), style: null) { UserData = fi, HoverColor = Color.Gold * 0.2f, SelectedColor = Color.Gold * 0.5f, - ToolTip = recipeTooltip }; + SetRecipeTooltip(frame, fi); var container = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true) { RelativeSpacing = 0.02f }; @@ -457,7 +452,7 @@ namespace Barotrauma.Items.Components itemIcon, scaleToFit: true) { Color = itemIcon == fi.TargetItem.Sprite ? fi.TargetItem.SpriteColor : fi.TargetItem.InventoryIconColor, - ToolTip = recipeTooltip + CanBeFocused = false }; } @@ -466,7 +461,7 @@ namespace Barotrauma.Items.Components { Padding = Vector4.Zero, AutoScaleVertical = true, - ToolTip = recipeTooltip + CanBeFocused = false }; new GUITextBlock(new RectTransform(new Vector2(0.85f, 1f), frame.RectTransform, Anchor.BottomRight), @@ -478,6 +473,20 @@ namespace Barotrauma.Items.Components } } + private void SetRecipeTooltip(GUIComponent component, FabricationRecipe recipe) + { + if (!recipe.RequiresRecipe) + { + component.ToolTip = RichString.Rich(recipe.TargetItem.Description); + } + else + { + component.ToolTip = AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem) ? + RichString.Rich(recipe.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Green)}‖{TextManager.Get("unlockedrecipe.true")}‖color:end‖") : + RichString.Rich(recipe.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{TextManager.Get("fabricatorrequiresrecipe")}‖color:end‖"); + } + } + private void InitInventoryUIs() { if (inputInventoryHolder != null) @@ -927,16 +936,24 @@ namespace Barotrauma.Items.Components } } - if (recipe.RequiresRecipe && recipe.HideIfNoRecipe) + if (recipe.RequiresRecipe) { - if (Character.Controlled != null) + if (recipe.HideIfNoRecipe) { - if (!AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem)) + bool anyOneHasRecipe = AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem); + if (Character.Controlled != null) { - child.Visible = false; - continue; + if (!anyOneHasRecipe) + { + child.Visible = false; + continue; + } } } + else + { + SetRecipeTooltip(child, recipe); + } } child.Visible = @@ -1147,7 +1164,16 @@ namespace Barotrauma.Items.Components var lines = description.WrappedText.Split('\n'); if (lines.Count <= 1) { break; } string newString = string.Join('\n', lines.Take(lines.Count - 1)); - description.Text = newString.Substring(0, newString.Length - 4) + "..."; + + if (newString.Length > 4) + { + description.Text = newString.Substring(0, newString.Length - 4) + "..."; + } + else + { + description.Text = newString + "..."; + } + description.CalculateHeightFromText(); description.ToolTip = richDescription; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs index 3c08f7fe7..f76b9506a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs @@ -443,6 +443,7 @@ namespace Barotrauma.Items.Components var wire = targetItem.GetComponent(); if (wire != null && wire.Connections.Any(c => c != null)) { return false; } + if (targetItem.Container is { NonInteractable: true }) { return false; } if (targetItem.Container?.GetComponent() is { DrawInventory: false } or { AllowAccess: false }) { return false; } if (targetItem.HasTag(Tags.TraitorMissionItem)) { return false; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs index 872b9be0c..adb44aa8e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs @@ -575,6 +575,22 @@ namespace Barotrauma.Items.Components pos /= c.Resources.Count; MineralClusters.Add((center: pos, resources: c.Resources)); } + + if (GameMain.GameSession != null) + { + foreach (var mission in GameMain.GameSession.Missions) + { + if (mission is MineralMission mineralMission) + { + foreach (var minerals in mineralMission.SpawnedResources) + { + MineralClusters.Add(( + center: new Vector2(minerals.Average(m => m.WorldPosition.X), minerals.Average(m => m.WorldPosition.Y)), + resources: minerals)); + } + } + } + } } else { @@ -823,18 +839,20 @@ namespace Barotrauma.Items.Components if (t.Entity is Character c && !c.IsUnconscious && c.Params.HideInSonar) { continue; } if (t.SoundRange <= 0.0f || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; } + float sonarSoundRange = t.SoundRange * t.SoundRangeOnSonarMultiplier; + float distSqr = Vector2.DistanceSquared(t.WorldPosition, transducerCenter); - if (distSqr > t.SoundRange * t.SoundRange * 2) { continue; } + if (distSqr > sonarSoundRange * sonarSoundRange * 2) { continue; } float dist = (float)Math.Sqrt(distSqr); if (dist > prevPassivePingRadius * Range && dist <= passivePingRadius * Range && Rand.Int(sonarBlips.Count) < 500) { Ping(t.WorldPosition, transducerCenter, - t.SoundRange * DisplayScale, 0, DisplayScale, range, + sonarSoundRange * DisplayScale, 0, DisplayScale, range, passive: true, pingStrength: 0.5f, needsToBeInSector: t); if (t.IsWithinSector(transducerCenter)) { - sonarBlips.Add(new SonarBlip(t.WorldPosition, fadeTimer: 1.0f, scale: MathHelper.Clamp(t.SoundRange / 2000, 1.0f, 5.0f))); + sonarBlips.Add(new SonarBlip(t.WorldPosition, fadeTimer: 1.0f, scale: MathHelper.Clamp(sonarSoundRange / 2000, 1.0f, 5.0f))); } } } @@ -977,7 +995,9 @@ namespace Barotrauma.Items.Components if (aiTarget.InDetectable) { continue; } if (aiTarget.SonarLabel.IsNullOrEmpty() || aiTarget.SoundRange <= 0.0f) { continue; } - if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange) + float sonarSoundRange = aiTarget.SoundRange * aiTarget.SoundRangeOnSonarMultiplier; + + if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < sonarSoundRange * sonarSoundRange) { DrawMarker(spriteBatch, aiTarget.SonarLabel.Value, diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs index e86923ef7..ad7305e89 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs @@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components get { return Vector2.Zero; } } - public override bool ShouldDrawHUD(Character character) + protected override bool ShouldDrawHUDComponentSpecific(Character character) { if (item.IsHidden) { return false; } if (!HasRequiredItems(character, false) || character.SelectedItem != item) { return false; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CircuitBox.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CircuitBox.cs index 9d8ba4214..cf4f06813 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CircuitBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CircuitBox.cs @@ -78,7 +78,7 @@ namespace Barotrauma.Items.Components } } - public override bool ShouldDrawHUD(Character character) + protected override bool ShouldDrawHUDComponentSpecific(Character character) => character == Character.Controlled && (character.SelectedItem == item || character.SelectedSecondaryItem == item); public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs index 50ee85985..d7d63d74d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs @@ -97,7 +97,7 @@ namespace Barotrauma.Items.Components MoveConnectedWires(amount); } - public override bool ShouldDrawHUD(Character character) + protected override bool ShouldDrawHUDComponentSpecific(Character character) { return character == Character.Controlled && character == user && (character.SelectedItem == item || character.SelectedSecondaryItem == item); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/StatusHUD.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/StatusHUD.cs index 9b999dbae..c6a7231fb 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/StatusHUD.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/StatusHUD.cs @@ -287,20 +287,24 @@ namespace Barotrauma.Items.Components texts.Add(target.CustomInteractHUDText); textColors.Add(GUIStyle.Green); } - if (!target.IsIncapacitated && target.IsPet) + if (equipper?.FocusedCharacter == target) { - texts.Add(CharacterHUD.GetCachedHudText("PlayHint", InputType.Use)); - textColors.Add(GUIStyle.Green); - } - if (equipper?.FocusedCharacter == target && target.CanBeHealedBy(equipper, checkFriendlyTeam: false)) - { - texts.Add(CharacterHUD.GetCachedHudText("HealHint", InputType.Health)); - textColors.Add(GUIStyle.Green); - } - if (target.CanBeDraggedBy(Character.Controlled)) - { - texts.Add(CharacterHUD.GetCachedHudText("GrabHint", InputType.Grab)); - textColors.Add(GUIStyle.Green); + if (!target.IsIncapacitated && target.IsPet && + target.AIController is EnemyAIController enemyAI && enemyAI.PetBehavior.CanPlayWith(Character.Controlled)) + { + texts.Add(CharacterHUD.GetCachedHudText("PlayHint", InputType.Use)); + textColors.Add(GUIStyle.Green); + } + if (target.CanBeHealedBy(equipper, checkFriendlyTeam: false)) + { + texts.Add(CharacterHUD.GetCachedHudText("HealHint", InputType.Health)); + textColors.Add(GUIStyle.Green); + } + if (target.CanBeDraggedBy(Character.Controlled)) + { + texts.Add(CharacterHUD.GetCachedHudText("GrabHint", InputType.Grab)); + textColors.Add(GUIStyle.Green); + } } if (target.IsUnconscious) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index 21f681e5e..3f7bfdfcd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -1597,7 +1597,8 @@ namespace Barotrauma { if (DraggingSlot == null || (!DraggingSlot.MouseOn())) { - Sprite sprite = DraggingItems.First().Prefab.InventoryIcon ?? DraggingItems.First().Sprite; + Item firstDraggingItem = DraggingItems.First(); + Sprite sprite = firstDraggingItem.OverrideInventorySprite ?? firstDraggingItem.Prefab.InventoryIcon ?? firstDraggingItem.Sprite; int iconSize = (int)(64 * GUI.Scale); float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f); @@ -1854,7 +1855,7 @@ namespace Barotrauma if (item != null && drawItem) { - Sprite sprite = item.Prefab.InventoryIcon ?? item.Sprite; + Sprite sprite = item.OverrideInventorySprite ?? item.Prefab.InventoryIcon ?? item.Sprite; float scale = Math.Min(Math.Min((rect.Width - 10) / sprite.size.X, (rect.Height - 10) / sprite.size.Y), 2.0f); Vector2 itemPos = rect.Center.ToVector2(); if (itemPos.Y > GameMain.GraphicsHeight) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs index eb371af3f..78be7c33a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs @@ -419,7 +419,7 @@ namespace Barotrauma if (fadeInBrokenSprite != null) { - float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f); + float d = MathHelper.Clamp(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.0f, 0.999f); fadeInBrokenSprite.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha, textureScale: Vector2.One * Scale, depth: d); @@ -435,7 +435,7 @@ namespace Barotrauma activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, RotationRad, Scale, activeSprite.effects, depth); if (fadeInBrokenSprite != null) { - float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f); + float d = MathHelper.Clamp(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.0f, 0.999f); fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, RotationRad, Scale, activeSprite.effects, d); } } @@ -885,7 +885,12 @@ namespace Barotrauma Spacing = (int)(25 * GUI.Scale) }; - var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUIStyle.LargeFont) { UserData = this }; + var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, + titleFont: GUIStyle.LargeFont, + dimOutDefaultValues: false) + { + UserData = this + }; activeEditors.Add(itemEditor); itemEditor.Children.First().Color = Color.Black * 0.7f; if (!inGame) @@ -1045,7 +1050,12 @@ namespace Barotrauma new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), listBox.Content.RectTransform), style: "HorizontalLine"); - var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, titleFont: GUIStyle.SubHeadingFont) { UserData = ic }; + var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, + titleFont: GUIStyle.SubHeadingFont, + dimOutDefaultValues: false) + { + UserData = ic + }; componentEditor.Children.First().Color = Color.Black * 0.7f; activeEditors.Add(componentEditor); @@ -1064,7 +1074,12 @@ namespace Barotrauma requiredItems.Add(relatedItem); } } - requiredItems.AddRange(ic.DisabledRequiredItems); + //if we have some actual requirements, no need to keep the empty requirement + //as a "placeholder" for the user to add requirements in the sub editor + if (ic.RequiredItems.None()) + { + requiredItems.AddRange(ic.DisabledRequiredItems); + } foreach (RelatedItem relatedItem in requiredItems) { @@ -1626,12 +1641,16 @@ namespace Barotrauma activeComponents.Clear(); activeComponents.AddRange(components); - foreach (MapEntity entity in linkedTo) + Controller controller = GetComponent(); + if (controller == null || controller.User != Character.Controlled || !controller.HideAllItemComponentHUDs) { - if (Prefab.IsLinkAllowed(entity.Prefab) && entity is Item i) + foreach (MapEntity entity in linkedTo) { - if (!i.DisplaySideBySideWhenLinked) { continue; } - activeComponents.AddRange(i.components); + if (Prefab.IsLinkAllowed(entity.Prefab) && entity is Item i) + { + if (!i.DisplaySideBySideWhenLinked) { continue; } + activeComponents.AddRange(i.components); + } } } @@ -1701,7 +1720,9 @@ namespace Barotrauma foreach (Character otherCharacter in Character.CharacterList) { if (otherCharacter != character && - otherCharacter.SelectedItem == this) + otherCharacter.SelectedItem == this && + // Prevent the in use message from being shown if a character is, for example, inside the deconstructor + !otherCharacter.IsAttachedToController()) { ItemInUseWarning.Visible = true; if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); } @@ -1751,6 +1772,11 @@ namespace Barotrauma } } + public void ClearActiveHUDs() + { + activeHUDs.Clear(); + } + readonly List texts = new(); public List GetHUDTexts(Character character, bool recreateHudTexts = true) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/ItemPrefab.cs index 7a7701b9e..6f5041c4f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/ItemPrefab.cs @@ -166,6 +166,14 @@ namespace Barotrauma subElement.GetAttributeBool("fadein", false), subElement.GetAttributePoint("offset", Point.Zero)); + if (brokenSprite.FadeIn && brokenSprite.MaxConditionPercentage <= 0.0f) + { + DebugConsole.AddWarning( + $"Potential error in item {Identifier}: a broken sprite that's set to fade in despite the max condition being 0."+ + " The sprite cannot fade in if it's set to only appear when the item is fully broken.", + ContentPackage); + } + int spriteIndex = 0; for (int i = 0; i < brokenSprites.Count && brokenSprites[i].MaxConditionPercentage < brokenSprite.MaxConditionPercentage; i++) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs index 129ef0958..49ab79cca 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Hull.cs @@ -16,15 +16,17 @@ namespace Barotrauma { public readonly UInt32 DecalId; public readonly int SpriteIndex; - public Vector2 NormalizedPos; + public readonly Vector2 NormalizedPos; public readonly float Scale; + public readonly float DecalAlpha; - public RemoteDecal(UInt32 decalId, int spriteIndex, Vector2 normalizedPos, float scale) + public RemoteDecal(UInt32 decalId, int spriteIndex, Vector2 normalizedPos, float scale, float decalAlpha) { DecalId = decalId; SpriteIndex = spriteIndex; NormalizedPos = normalizedPos; Scale = scale; + DecalAlpha = decalAlpha; } } @@ -696,7 +698,7 @@ namespace Barotrauma var decal = decalEventData.Decal; int decalIndex = decals.IndexOf(decal); msg.WriteByte((byte)(decalIndex < 0 ? 255 : decalIndex)); - msg.WriteRangedSingle(decal.BaseAlpha, 0.0f, 1.0f, 8); + msg.WriteRangedSingle(decal.BaseAlpha, 0f, 1f, 8); break; default: throw new Exception($"Malformed hull event: did not expect {eventData.GetType().Name}"); @@ -752,7 +754,9 @@ namespace Barotrauma float normalizedXPos = msg.ReadRangedSingle(0.0f, 1.0f, 8); float normalizedYPos = msg.ReadRangedSingle(0.0f, 1.0f, 8); float decalScale = msg.ReadRangedSingle(0.0f, 2.0f, 12); - remoteDecals.Add(new RemoteDecal(decalId, spriteIndex, new Vector2(normalizedXPos, normalizedYPos), decalScale)); + float decalAlpha = msg.ReadRangedSingle(0f, 1f, 8); + + remoteDecals.Add(new RemoteDecal(decalId, spriteIndex, new Vector2(normalizedXPos, normalizedYPos), decalScale, decalAlpha)); } break; case EventType.BallastFlora: @@ -804,7 +808,8 @@ namespace Barotrauma decalPosX += Submarine.Position.X; decalPosY += Submarine.Position.Y; } - AddDecal(remoteDecal.DecalId, new Vector2(decalPosX, decalPosY), remoteDecal.Scale, isNetworkEvent: true, spriteIndex: remoteDecal.SpriteIndex); + Decal decal = AddDecal(remoteDecal.DecalId, new Vector2(decalPosX, decalPosY), remoteDecal.Scale, isNetworkEvent: true, spriteIndex: remoteDecal.SpriteIndex); + decal.BaseAlpha = remoteDecal.DecalAlpha; } remoteDecals.Clear(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs index 8202240aa..9c145eca0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs @@ -296,13 +296,9 @@ namespace Barotrauma.Lights light.Priority = lightPriority(range, light); - int i = 0; - while (i < activeLights.Count && light.Priority < activeLights[i].Priority) - { - i++; - } - activeLights.Insert(i, light); + activeLights.Add(light); } + activeLights.Sort(static (a, b) => b.Priority.CompareTo(a.Priority)); ActiveLightCount = activeLights.Count; float lightPriority(float range, LightSource light) @@ -332,7 +328,7 @@ namespace Barotrauma.Lights activeLights.Remove(activeShadowCastingLights[i]); } } - activeLights.Sort((l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime)); + activeLights.Sort(static (l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime)); //draw light sprites attached to characters //render into a separate rendertarget using alpha blending (instead of on top of everything else with alpha blending) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs index e54f37f21..2912d88f2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs @@ -50,8 +50,14 @@ namespace Barotrauma.Lights [Serialize("0, 0", IsPropertySaveable.Yes), Editable(ValueStep = 1, DecimalCount = 1, MinValueFloat = -1000f, MaxValueFloat = 1000f)] public Vector2 Offset { get; set; } + public float RotationRad { get; private set; } + [Serialize(0f, IsPropertySaveable.Yes), Editable(MinValueFloat = -360, MaxValueFloat = 360, ValueStep = 1, DecimalCount = 0)] - public float Rotation { get; set; } + public float Rotation + { + get => MathHelper.ToDegrees(RotationRad); + set => RotationRad = MathHelper.ToRadians(value); + } [Serialize(false, IsPropertySaveable.Yes, "Directional lights only shine in \"one direction\", meaning no shadows are cast behind them."+ " Note that this does not affect how the light texture is drawn: if you want something like a conical spotlight, you should use an appropriate texture for that.")] @@ -314,6 +320,10 @@ namespace Barotrauma.Lights private float prevCalculatedRotation; private float rotation; + + /// + /// Current rotation in radians. Note that LightSourceParams.RotationRad also affects the final rotation of the light. + /// public float Rotation { get { return rotation; } @@ -322,7 +332,7 @@ namespace Barotrauma.Lights if (Math.Abs(value - rotation) < 0.001f) { return; } rotation = value; - dir = new Vector2(MathF.Cos(rotation), -MathF.Sin(rotation)); + RefreshDirection(); if (Math.Abs(rotation - prevCalculatedRotation) < RotationRecalculationThreshold && vertices != null) { @@ -486,6 +496,9 @@ namespace Barotrauma.Lights break; } } + //make sure the rotation defined in the parameters is taken into account + RefreshDirection(); + NeedsRecalculation = true; } public LightSource(LightSourceParams lightSourceParams) @@ -497,6 +510,9 @@ namespace Barotrauma.Lights { DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement, invert: true); } + //make sure the rotation defined in the parameters is taken into account + RefreshDirection(); + NeedsRecalculation = true; } public LightSource(Vector2 position, float range, Color color, Submarine submarine, bool addLight=true) @@ -511,6 +527,14 @@ namespace Barotrauma.Lights if (addLight) { GameMain.LightManager.AddLight(this); } } + /// + /// Refresh the direction vector of the light (which is used for calculating shadows) based on the rotation and + /// + private void RefreshDirection() + { + dir = new Vector2(MathF.Cos(rotation - LightSourceParams.RotationRad), -MathF.Sin(rotation - LightSourceParams.RotationRad)); + } + public void Update(float time) { float brightness = 1.0f; @@ -773,9 +797,6 @@ namespace Barotrauma.Lights float boundsExtended = TextureRange; if (OverrideLightTexture != null) { - float cosAngle = (float)Math.Cos(rotation); - float sinAngle = -(float)Math.Sin(rotation); - var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height); Vector2 origin = OverrideLightTextureOrigin; @@ -790,8 +811,11 @@ namespace Barotrauma.Lights origin *= TextureRange; - drawOffset.X = -origin.X * cosAngle - origin.Y * sinAngle; - drawOffset.Y = origin.X * sinAngle + origin.Y * cosAngle; + //rotate the origin based on the direction + float cos = dir.X; + float sin = dir.Y; + drawOffset.X = -origin.X * cos - origin.Y * sin; + drawOffset.Y = origin.X * sin + origin.Y * cos; } //add a square-shaped boundary to make sure we've got something to construct the triangles from @@ -1536,7 +1560,6 @@ namespace Barotrauma.Lights Vector2 offset = ParentSub == null ? Vector2.Zero : ParentSub.DrawPosition; lightEffect.World = Matrix.CreateTranslation(-new Vector3(position, 0.0f)) * - Matrix.CreateRotationZ(MathHelper.ToRadians(LightSourceParams.Rotation)) * Matrix.CreateTranslation(new Vector3(position + offset + translateVertices, 0.0f)) * transform; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Structure.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Structure.cs index e15d5bd48..4db180177 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Structure.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Structure.cs @@ -193,7 +193,12 @@ namespace Barotrauma { CanTakeKeyBoardFocus = false }; - var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUIStyle.LargeFont) { UserData = this }; + var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, + titleFont: GUIStyle.LargeFont, + dimOutDefaultValues: false) + { + UserData = this + }; if (editor.Fields.TryGetValue(nameof(Scale).ToIdentifier(), out GUIComponent[] scaleFields) && scaleFields.FirstOrDefault() is GUINumberInput scaleInput) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs index c0656420b..96f56708a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs @@ -30,6 +30,13 @@ namespace Barotrauma.Networking { DualStack = GameSettings.CurrentConfig.UseDualModeSockets }; + if (NetConfig.UseLenientHandshake) + { + // More lenient timeouts for local testing, so the server would start even without perfect conditions + netPeerConfiguration.ConnectionTimeout = 60.0f; + netPeerConfiguration.ResendHandshakeInterval = 5.0f; + netPeerConfiguration.MaximumHandshakeAttempts = 20; + } if (endpoint.NetEndpoint.Address.AddressFamily == AddressFamily.InterNetworkV6) { netPeerConfiguration.LocalAddress = System.Net.IPAddress.IPv6Any; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs index 77c3a4005..13f701023 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs @@ -351,7 +351,7 @@ namespace Barotrauma { Level.Loaded.DrawBack(graphics, spriteBatch, cam); } - else if (GameMain.GameSession.GameMode is TestGameMode testMode) + else if (GameMain.GameSession?.GameMode is TestGameMode testMode) { graphics.Clear(testMode.BackgroundParams.BackgroundColor); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen/MainMenuScreen.cs index 61f536f38..e42d09894 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen/MainMenuScreen.cs @@ -49,6 +49,9 @@ namespace Barotrauma private GUITextBox serverNameBox, passwordBox, maxPlayersBox; private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox; private GUIDropDown languageDropdown, serverExecutableDropdown; +#if DEBUG + private GUITickBox lenientHandshakeBox; +#endif private readonly GUIButton joinServerButton, hostServerButton; private readonly GUIFrame modsButtonContainer; @@ -1075,7 +1078,7 @@ namespace Barotrauma "-public", isPublicBox.Selected.ToString(), "-playstyle", ((PlayStyle)playstyleBanner.UserData).ToString(), "-banafterwrongpassword", wrongPasswordBanBox.Selected.ToString(), - "-karmaenabled", (!karmaBox.Selected).ToString(), + "-karmaenabled", (karmaBox.Selected).ToString(), "-maxplayers", maxPlayersBox.Text, "-language", languageDropdown.SelectedData.ToString() }; @@ -1114,6 +1117,13 @@ namespace Barotrauma int ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1); arguments.Add("-ownerkey"); arguments.Add(ownerKey.ToString()); +#if DEBUG + if (lenientHandshakeBox.Selected) + { + arguments.Add("-lenienthandshake"); + NetConfig.UseLenientHandshake = true; + } +#endif var processInfo = new ProcessStartInfo { @@ -1368,7 +1378,7 @@ namespace Barotrauma } int maxPlayers = Math.Clamp(maxPlayersElement, min: 1, max: NetConfig.MaxPlayers); - var karmaEnabled = serverSettings.GetAttributeBool("karmaenabled", true); + var karmaEnabled = serverSettings.GetAttributeBool("karmaenabled", false); var selectedPlayStyle = serverSettings.GetAttributeEnum("playstyle", PlayStyle.Casual); Vector2 textLabelSize = new Vector2(1.0f, 0.05f); @@ -1579,10 +1589,18 @@ namespace Barotrauma karmaBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1.0f), tickboxAreaLower.RectTransform), TextManager.Get("HostServerKarmaSetting")) { - Selected = !karmaEnabled, + Selected = karmaEnabled, ToolTip = TextManager.Get("hostserverkarmasettingtooltip") }; +#if DEBUG + lenientHandshakeBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1.0f), tickboxAreaLower.RectTransform), "DEBUG: Lenient server startup timeouts") + { + Selected = true, + ToolTip = "Start with more lenient Lidgren handshake timeouts. The server is more likely to start even when running multiple instances on the same machine under heavy load." + }; +#endif + tickboxAreaLower.RectTransform.IsFixedSize = true; //spacing @@ -1671,8 +1689,8 @@ namespace Barotrauma if (string.IsNullOrEmpty(remoteContentUrl)) { return; } try { - var client = new RestClient(remoteContentUrl); - var request = new RestRequest("MenuContent.xml", Method.GET); + var client = RestFactory.CreateClient(remoteContentUrl); + var request = RestFactory.CreateRequest("MenuContent.xml"); TaskPool.Add("RequestMainMenuRemoteContent", client.ExecuteAsync(request), RemoteContentReceived); } @@ -1693,12 +1711,17 @@ namespace Barotrauma try { if (!t.TryGetResult(out IRestResponse remoteContentResponse)) { throw new Exception("Task did not return a valid result"); } + if (remoteContentResponse.ErrorException != null) + { + DebugConsole.AddWarning($"Connection error: Failed to fetch remote main menu content " + + $"({remoteContentResponse.ErrorException.Message})."); + return; + } if (remoteContentResponse.StatusCode != HttpStatusCode.OK) { DebugConsole.AddWarning( "Failed to receive remote main menu content. " + - "There may be an issue with your internet connection, or the master server might be temporarily unavailable " + - $"(error code: {remoteContentResponse.StatusCode})"); + $"The master server might be temporarily unavailable (HTTP error: {remoteContentResponse.StatusCode})"); return; } string xml = remoteContentResponse.Content; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs index 1e3393406..2aa54d20c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs @@ -398,7 +398,7 @@ namespace Barotrauma string dir = path.RemoveFromEnd(ModReceiver.Extension, StringComparison.OrdinalIgnoreCase); SaveUtil.DecompressToDirectory(path, dir); - var result = ContentPackage.TryLoad(Path.Combine(dir, ContentPackage.FileListFileName)); + var result = ContentPackage.TryLoad(Path.Combine(dir, ContentPackage.FileListFileName).CleanUpPathCrossPlatform()); if (!result.TryUnwrapSuccess(out var newPackage)) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index a42a29457..206009ddc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -733,6 +733,8 @@ namespace Barotrauma AutoHideScrollBar = false, OnSelected = (component, userdata) => { + //if we're clicking on a checkbox (toggle visibility) on the list, don't select the entry on the list + if (GUI.MouseOn is GUITickBox) { return false; } //toggling selection is not how listboxes normally work, need to do that manually here SoundPlayer.PlayUISound(GUISoundType.Select); if (layerList.SelectedData == userdata) @@ -3253,6 +3255,20 @@ namespace Barotrauma = new GUITextBox(new RectTransform((1.0f, 0.15f), saveInPackageLayout.RectTransform), createClearButton: true); + packToSaveInFilter.OnTextChanged += (GUITextBox textBox, string text) => + { + + foreach (GUIComponent child in packageToSaveInList.Content.Children) + { + child.Visible = + // Get the pkgText from below + !(child.GetChild()?.GetChild() is GUITextBlock textBlock && + !textBlock.Text.Contains(packToSaveInFilter.Text, StringComparison.OrdinalIgnoreCase)); + } + + return true; + }; + GUILayoutGroup addItemToPackageToSaveList(LocalizedString itemText, ContentPackage p) { var listItem = new GUIFrame(new RectTransform((1.0f, 0.15f), packageToSaveInList.Content.RectTransform), @@ -3273,28 +3289,26 @@ namespace Barotrauma return retVal; } + ContentPackage ownerPkg = null; + #if DEBUG //this is a debug-only option so I won't bother submitting it for localization var modifyVanillaListItem = addItemToPackageToSaveList("Modify Vanilla content package", ContentPackageManager.VanillaCorePackage); var modifyVanillaListIcon = modifyVanillaListItem.GetChild(); GUIStyle.Apply(modifyVanillaListIcon, "WorkshopMenu.EditButton"); + + if (MainSub?.Info != null && IsVanillaSub(MainSub.Info)) + { + ownerPkg = ContentPackageManager.VanillaCorePackage; + } #endif var newPackageListItem = addItemToPackageToSaveList(TextManager.Get("CreateNewLocalPackage"), null); var newPackageListIcon = newPackageListItem.GetChild(); var newPackageListText = newPackageListItem.GetChild(); GUIStyle.Apply(newPackageListIcon, "NewContentPackageIcon"); - new GUICustomComponent(new RectTransform(Vector2.Zero, saveInPackageLayout.RectTransform), - onUpdate: (f, component) => - { - foreach (GUIComponent contentChild in packageToSaveInList.Content.Children) - { - contentChild.Visible &= !(contentChild.GetChild()?.GetChild() is GUITextBlock tb && - !tb.Text.Contains(packToSaveInFilter.Text, StringComparison.OrdinalIgnoreCase)); - } - }); - ContentPackage ownerPkg = null; - if (MainSub?.Info != null) { ownerPkg = GetLocalPackageThatOwnsSub(MainSub.Info); } + + if (ownerPkg == null && MainSub?.Info != null) { ownerPkg = GetLocalPackageThatOwnsSub(MainSub.Info); } foreach (var p in ContentPackageManager.LocalPackages) { var packageListItem = addItemToPackageToSaveList(p.Name, p); @@ -3849,6 +3863,10 @@ namespace Barotrauma return true; }; + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), deleteButtonHolder.RectTransform), TextManager.Get("DragAndDropSubmarineTip").Fallback(LocalizedString.EmptyString), textAlignment: Alignment.Center, font: GUIStyle.Font) + { + Wrap = true + }; if (AutoSaveInfo?.Root != null) { @@ -4486,6 +4504,7 @@ namespace Barotrauma public void ReconstructLayers() { + Dictionary previousLayers = Layers.ToDictionary(); ClearLayers(); foreach (MapEntity entity in MapEntity.MapEntityList) { @@ -4494,6 +4513,13 @@ namespace Barotrauma Layers.TryAdd(entity.Layer, new LayerData(!entity.IsLayerHidden)); } } + foreach ((string layerName, LayerData data) in previousLayers) + { + if (Layers.ContainsKey(layerName)) + { + Layers[layerName] = data; + } + } UpdateLayerPanel(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs index 668b1bde8..22b885e50 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs @@ -26,6 +26,8 @@ namespace Barotrauma public static DateTime NextCommandPush; public static Tuple CommandBuffer; + private bool dimOutDefaultValues; + private bool isReadonly; public bool Readonly { @@ -316,16 +318,17 @@ namespace Barotrauma } } - public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, bool inGame, bool showName, string style = "", int elementHeight = 24, GUIFont titleFont = null) + public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, bool inGame, bool showName, string style = "", int elementHeight = 24, GUIFont titleFont = null, bool dimOutDefaultValues = true) : this(parent, entity, inGame ? SerializableProperty.GetProperties(entity).Union(SerializableProperty.GetProperties(entity).Where(p => p.GetAttribute()?.IsEditable(entity) ?? false)) - : SerializableProperty.GetProperties(entity).Where(p => p.GetAttribute()?.IsEditable(entity) ?? true), showName, style, elementHeight, titleFont) + : SerializableProperty.GetProperties(entity).Where(p => p.GetAttribute()?.IsEditable(entity) ?? true), showName, style, elementHeight, titleFont, dimOutDefaultValues) { } - public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, IEnumerable properties, bool showName, string style = "", int elementHeight = 24, GUIFont titleFont = null) + public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, IEnumerable properties, bool showName, string style = "", int elementHeight = 24, GUIFont titleFont = null, bool dimOutDefaultValues = true) : base(style, new RectTransform(Vector2.One, parent)) { + this.dimOutDefaultValues = dimOutDefaultValues; elementHeight = (int)(elementHeight * GUI.Scale); var tickBoxStyle = GUIStyle.GetComponentStyle("GUITickBox"); var textBoxStyle = GUIStyle.GetComponentStyle("GUITextBox"); @@ -523,9 +526,67 @@ namespace Barotrauma { propertyField = CreateStringField(entity, property, value.ToString(), displayName, toolTip); } + if (propertyField != null && dimOutDefaultValues) + { + UpdateTextColors(property, entity, propertyField); + } return propertyField; } + + private void UpdateTextColors(SerializableProperty property, object parentObject, GUIComponent parentElement) + { + if (!dimOutDefaultValues) { return; } + + bool isSetToDefaultValue = false; + object currentValue = property.GetValue(parentObject); + foreach (var attribute in property.Attributes.OfType()) + { + if (XMLExtensions.DefaultValueEquals(attribute.DefaultValue, currentValue) || + //treat null and empty strings as identical, because there's no way to differentiate between those in the editor + (currentValue == null && attribute.DefaultValue is string defaultValueStr && defaultValueStr.IsNullOrEmpty())) + { + isSetToDefaultValue = true; + break; + } + } + foreach (var component in parentElement.GetAllChildren()) + { + UpdateTextColors(component, isSetToDefaultValue); + } + } + + private void UpdateTextColors(GUIComponent component, bool isSetToDefaultValue) + { + if (!dimOutDefaultValues) { return; } + + if (component is GUINumberInput numberInput) + { + SetTextColor(numberInput.TextBox.TextBlock); + } + else if (component is GUIDropDown dropDown) + { + SetTextColor(dropDown.Button.TextBlock); + } + else if (component is GUITextBox textBox) + { + SetTextColor(textBox.TextBlock); + } + else if (component is GUITextBlock textBlock) + { + SetTextColor(textBlock); + } + else if (component is GUITickBox tickBox) + { + SetTextColor(tickBox.TextBlock); + } + + void SetTextColor(GUITextBlock textBlock) + { + textBlock.TextColor = new Color(textBlock.TextColor, alpha: isSetToDefaultValue ? 0.5f : 1.0f); + } + } + public GUIComponent CreateBoolField(ISerializableEntity entity, SerializableProperty property, bool value, LocalizedString displayName, LocalizedString toolTip) { var editableAttribute = property.GetAttribute(); @@ -564,6 +625,7 @@ namespace Barotrauma tickBox.Selected = propertyValue; tickBox.Flash(Color.Red); } + UpdateTextColors(property, entity, tickBox); return true; } }; @@ -611,6 +673,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; refresh += () => { @@ -654,6 +717,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; HandleSetterValueTampering(numberInput, () => property.GetFloatValue(entity)); @@ -711,6 +775,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); return true; }; refresh += () => @@ -829,6 +894,7 @@ namespace Barotrauma TrySendNetworkUpdate(entity, property); textBox.Text = StripPrefabTags(property.GetValue(entity).ToString()); textBox.Flash(GUIStyle.Green, flashDuration: 1f); + UpdateTextColors(property, entity, frame); } //restore the entities that were selected before applying MapEntity.SelectedList.Clear(); @@ -973,6 +1039,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; fields[i] = numberInput; } @@ -1046,6 +1113,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; HandleSetterValueTampering(numberInput, () => { @@ -1126,6 +1194,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; fields[i] = numberInput; } @@ -1206,6 +1275,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; fields[i] = numberInput; } @@ -1299,6 +1369,7 @@ namespace Barotrauma TrySendNetworkUpdate(entity, property); colorBox.Color = colorBox.HoverColor = colorBox.PressedColor = colorBox.SelectedTextColor = newVal; } + UpdateTextColors(property, entity, frame); }; colorBox.Color = colorBox.HoverColor = colorBox.PressedColor = colorBox.SelectedTextColor = (Color)property.GetValue(entity); fields[i] = numberInput; @@ -1373,6 +1444,7 @@ namespace Barotrauma { TrySendNetworkUpdate(entity, property); } + UpdateTextColors(property, entity, frame); }; fields[i] = numberInput; } @@ -1437,6 +1509,7 @@ namespace Barotrauma TrySendNetworkUpdate(entity, property); textBox.Flash(color: GUIStyle.Green, flashDuration: 1f); } + UpdateTextColors(property, entity, frame); } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/SpamServerFilter.cs b/Barotrauma/BarotraumaClient/ClientSource/SpamServerFilter.cs index 2214848d4..47d3d1b58 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/SpamServerFilter.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/SpamServerFilter.cs @@ -387,13 +387,11 @@ These will hide all servers that have a discord.gg link in their name or descrip try { - var client = new RestClient($"{remoteContentUrl}spamfilter") - { - CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore) - }; + var client = RestFactory.CreateClient($"{remoteContentUrl}spamfilter"); + client.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore); client.AddDefaultHeader("Cache-Control", "no-cache"); client.AddDefaultHeader("Pragma", "no-cache"); - var request = new RestRequest("serve_spamlist.php", Method.GET); + var request = RestFactory.CreateRequest("serve_spamlist.php"); TaskPool.Add("RequestGlobalSpamFilter", client.ExecuteAsync(request), RemoteContentReceived); } catch (Exception e) @@ -410,12 +408,18 @@ These will hide all servers that have a discord.gg link in their name or descrip try { if (!t.TryGetResult(out IRestResponse? remoteContentResponse)) { throw new Exception("Task did not return a valid result"); } + if (remoteContentResponse.ErrorException != null) + { + DebugConsole.AddWarning( + "Connection error: Failed to receive global spam filter " + + $"({remoteContentResponse.ErrorException.Message})."); + return; + } if (remoteContentResponse.StatusCode != HttpStatusCode.OK) { DebugConsole.AddWarning( - "Failed to receive global spam filter." + - "There may be an issue with your internet connection, or the master server might be temporarily unavailable " + - $"(error code: {remoteContentResponse.StatusCode})"); + "Failed to receive global spam filter. " + + $"The master server might be temporarily unavailable, HTTP status: {remoteContentResponse.StatusCode}"); return; } string data = remoteContentResponse.Content; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs index cc1ef9c79..5f33df3bc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs @@ -23,13 +23,27 @@ namespace Barotrauma.Steam "submarine", "item", "monster", - "art", "mission", + "outpost", + "beaconstation", + "wreck", + "ruin", + "weapons", + "medical", + "equipment", + "art", "event set", "total conversion", + "gamemode", + "gameplaymechanics", "environment", "item assembly", "language", + "qol", + "clientside", + "serverside", + "outdated", + "library" }.ToIdentifiers().ToImmutableArray(); public class ItemThumbnail : IDisposable @@ -113,10 +127,14 @@ namespace Barotrauma.Steam string? thumbnailUrl = item.PreviewImageUrl; if (thumbnailUrl.IsNullOrWhiteSpace()) { return null; } - var client = new RestClient(thumbnailUrl); - var request = new RestRequest(".", Method.GET); + var client = RestFactory.CreateClient(thumbnailUrl); + var request = RestFactory.CreateRequest("."); IRestResponse response = await client.ExecuteAsync(request, cancellationToken); - if (response is { StatusCode: System.Net.HttpStatusCode.OK, ResponseStatus: ResponseStatus.Completed }) + if (response.ErrorException != null) + { + DebugConsole.NewMessage($"Connection error: Failed to load workshop item thumbnail for {item.Id} ({response.ErrorException.Message})."); + } + else if (response is { StatusCode: System.Net.HttpStatusCode.OK, ResponseStatus: ResponseStatus.Completed }) { using var dataStream = new System.IO.MemoryStream(); await dataStream.WriteAsync(response.RawBytes, cancellationToken); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs index 91038dab5..3c7ec45b2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs @@ -535,9 +535,9 @@ namespace Barotrauma.Steam = new GUIListBox(rectT, style: null, isHorizontal: false) { UseGridLayout = true, - ScrollBarEnabled = false, + ScrollBarEnabled = true, ScrollBarVisible = false, - HideChildrenOutsideFrame = false, + HideChildrenOutsideFrame = true, Spacing = GUI.IntScale(4) }; tagsList.Content.ClampMouseRectToParent = false; diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 89eec0609..0fd9b5f60 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 4dcfb80d3..ced8f9692 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 086a023fa..a62c8335f 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2024 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 1cc47a6fc..050b41dce 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 11fed9443..b255712af 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/EventManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/EventManager.cs index 6850a5174..50e04783c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/EventManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/EventManager.cs @@ -79,6 +79,15 @@ namespace Barotrauma convAction.SelectedOption = selectedOption; if (convAction.Options.Any() && !convAction.GetEndingOptions().Contains(selectedOption)) { + var option = convAction.Options[selectedOption]; + if (option.ForceSay && sender.Character != null) + { + sender.Character.ForceSay( + option.ForceSayText.IsNullOrEmpty() ? TextManager.Get(option.Text).Fallback(option.Text) : TextManager.Get(option.ForceSayText).Fallback(option.ForceSayText), + option.ForceSayInRadio, + option.ForceSayRemoveQuotes); + } + foreach (Client c in convAction.TargetClients) { if (c == sender) { continue; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs index 736c98542..836dc9f1c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs @@ -133,7 +133,7 @@ namespace Barotrauma switch (winCondition) { case WinCondition.LastManStanding: - if (crews[0].Count == 0 || crews[1].Count == 0) + if (crews[0].Count == 0 && crews[1].Count == 0) { //if there are no characters in either crew, end the round teamDead[0] = teamDead[1] = true; diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameMain.cs b/Barotrauma/BarotraumaServer/ServerSource/GameMain.cs index ecada43df..2d50a32ea 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameMain.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameMain.cs @@ -230,6 +230,9 @@ namespace Barotrauma //handled in TryStartChildServerRelay i += 2; break; + case "-lenienthandshake": + NetConfig.UseLenientHandshake = true; + break; } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Controller.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Controller.cs index 8d8fe2933..5a6f1708c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Controller.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Controller.cs @@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null) { msg.WriteBoolean(State); - msg.WriteUInt16(user == null ? (ushort)0 : user.ID); + msg.WriteUInt16(User == null || User.Removed ? (ushort)0 : User.ID); } } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Repairable.cs index 089fc03df..f37295790 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Repairable.cs @@ -16,8 +16,11 @@ namespace Barotrauma.Items.Components public void ServerEventRead(IReadMessage msg, Client c) { if (c.Character == null) { return; } - var requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2); - var QTESuccess = msg.ReadBoolean(); + FixActions requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2); + bool QTESuccess = msg.ReadBoolean(); + + if (!item.CanClientAccess(c) || !HasRequiredItems(c.Character, addMessage: false)) { return; } + if (requestedFixAction != FixActions.None) { if (!c.Character.IsTraitor && requestedFixAction == FixActions.Sabotage) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Inventory.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Inventory.cs index 3d85e08ad..38e09b975 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Inventory.cs @@ -121,9 +121,9 @@ namespace Barotrauma if (shouldBeRemoved) { bool itemAccessDenied = prevItems.Contains(item) && // if the item was in the inventory before - !itemAccessibility[item] && // and the sender is not allowed to access it - (item.PreviousParentInventory == null || // and either the item has no previous inventory - !sender.Character.CanAccessInventory(item.PreviousParentInventory)); // or the sender can't access the previous inventory + !itemAccessibility[item] && // and the sender is not allowed to access it + (item.PreviousParentInventory == null || // and either the item has no previous inventory + !sender.Character.CanAccessInventory(item.PreviousParentInventory)); // or the sender can't access the previous inventory if (itemAccessDenied) { @@ -136,7 +136,7 @@ namespace Barotrauma Item droppedItem = item; Entity prevOwner = Owner; Inventory previousInventory = droppedItem.ParentInventory; - droppedItem.Drop(null); + droppedItem.Drop(sender.Character); droppedItem.PreviousParentInventory = previousInventory; var previousCharacterInventory = prevOwner switch @@ -188,9 +188,18 @@ namespace Barotrauma if (holdable != null && !holdable.CanBeDeattached()) { continue; } - bool itemAccessDenied = !prevItems.Contains(item) && !itemAccessibility[item] && - (sender.Character == null || item.PreviousParentInventory == null || !sender.Character.CanAccessInventory(item.PreviousParentInventory)); - + bool itemAccessDenied = !prevItems.Contains(item) && + !itemAccessibility[item] && + (item.PreviousParentInventory == null || + !sender.Character.CanAccessInventory(item.PreviousParentInventory)); + + // Prevent modified clients from being able to steal items from characters by item swapping with an existing item + // due to drag and drop being enabled + if (!sender.Character.CanAccessInventory(this, CharacterInventory.AccessLevel.AllowBotsAndPets) && GetItemAt(slotIndex) != null) + { + itemAccessDenied = true; + } + //more restricted "adding" of handcuffs: we can't allow putting handcuffs on a player just because dragging and dropping is allowed if (item.HasTag(Tags.HandLockerItem) && !itemAccessDenied) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs index 0a66bbd08..216aeafa8 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs @@ -12,8 +12,6 @@ namespace Barotrauma { private CoroutineHandle logPropertyChangeCoroutine; - public Inventory PreviousParentInventory; - public override Sprite Sprite { get { return base.Prefab?.Sprite; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs b/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs index cfb0592cd..705c06fa1 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs @@ -112,6 +112,7 @@ namespace Barotrauma msg.WriteRangedSingle(normalizedXPos, 0.0f, 1.0f, 8); msg.WriteRangedSingle(normalizedYPos, 0.0f, 1.0f, 8); msg.WriteRangedSingle(decal.Scale, 0f, 2f, 12); + msg.WriteRangedSingle(decal.BaseAlpha, 0f, 1f, 8); } break; case BallastFloraEventData ballastFloraEventData: @@ -251,7 +252,7 @@ namespace Barotrauma break; case EventType.Decal: byte decalIndex = msg.ReadByte(); - float decalAlpha = msg.ReadRangedSingle(0.0f, 1.0f, 255); + float decalAlpha = msg.ReadRangedSingle(0f, 1f, 8); if (decalIndex < 0 || decalIndex >= decals.Count) { return; } if (c.Character != null && c.Character.AllowInput && c.Character.HeldItems.Any(it => it.GetComponent() != null)) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs index 8ffc5a751..06ed826ff 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs @@ -66,6 +66,9 @@ namespace Barotrauma.Networking txt = msg.ReadString() ?? ""; } + // Sanitize incoming text message from client so they can't use RichString features + txt = txt.Replace('‖', ' '); + if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { return; } c.LastSentChatMsgID = ID; diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs index 6bab9e4ec..eb0442453 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs @@ -244,6 +244,8 @@ namespace Barotrauma Character targetCharacter = inventory.Owner as Character; if (yoinker == null || item == null || thiefCharacter == null || targetCharacter == null || thiefCharacter == targetCharacter) { return; } + + if (thiefCharacter.TeamID != targetCharacter.TeamID) { return; } if (targetClient == null && (!DangerousItemStealBots || targetCharacter.AIController == null)) { return; } @@ -261,7 +263,7 @@ namespace Barotrauma } Item foundItem = null; - if (isValid(item)) + if (IsValid(item)) { foundItem = item; } @@ -269,7 +271,7 @@ namespace Barotrauma { foreach (Item containedItem in item.ContainedItems) { - if (isValid(containedItem)) + if (IsValid(containedItem)) { foundItem = containedItem; break; @@ -277,16 +279,19 @@ namespace Barotrauma } } - static bool isValid(Item item) + static bool IsValid(Item item) { - return item.GetComponent() != null || item.GetComponent() != null || item.GetComponent() != null; + return item.GetComponent() != null || IsWeapon(item); + } + static bool IsWeapon(Item item) + { + //a threshold of 10 excludes things like tools, all "proper weapons" seem to have a priority higher than that + return item.Components.Max(c => c.CombatPriority) > 10.0f || item.HasTag(Tags.Weapon); } if (foundItem == null) { return; } bool isIdCard = foundItem.GetComponent() != null; - bool isWeapon = foundItem.GetComponent() != null || foundItem.GetComponent() != null; - if (isIdCard) { string name = string.Empty; @@ -325,7 +330,7 @@ namespace Barotrauma JobPrefab clientJob = yoinker.CharacterInfo?.Job?.Prefab; // security officers receive less karma penalty - if (clientJob != null && clientJob.Identifier == "securityofficer" && isWeapon) + if (clientJob != null && clientJob.Identifier == "securityofficer" && IsWeapon(foundItem)) { karmaDecrease *= 0.5f; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/LidgrenServerPeer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/LidgrenServerPeer.cs index 79bfedd93..b320a8d6d 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/LidgrenServerPeer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/LidgrenServerPeer.cs @@ -32,6 +32,13 @@ namespace Barotrauma.Networking Port = serverSettings.Port, DualStack = GameSettings.CurrentConfig.UseDualModeSockets }; + if (NetConfig.UseLenientHandshake) + { + // More lenient timeouts for local testing, so the server would start even without perfect conditions + netPeerConfiguration.ConnectionTimeout = 60.0f; + netPeerConfiguration.ResendHandshakeInterval = 5.0f; + netPeerConfiguration.MaximumHandshakeAttempts = 20; + } netPeerConfiguration.DisableMessageType( NetIncomingMessageType.DebugMessage diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs index e1e2a6c78..7c78adc98 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs @@ -582,6 +582,23 @@ namespace Barotrauma.Networking teamSpecificState.RespawnItems.AddRange(AutoItemPlacer.RegenerateLoot(respawnShuttle, respawnContainer)); } } + else if (character.InWater) + { + if (divingSuitPrefab != null) + { + var divingSuit = new Item(divingSuitPrefab, character.Position, respawnSub); + Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit)); + character.Inventory.TryPutItem(divingSuit, user: null, allowedSlots: divingSuit.AllowedSlots); + teamSpecificState.RespawnItems.Add(divingSuit); + if (oxyPrefab != null && divingSuit.GetComponent() != null) + { + var oxyTank = new Item(oxyPrefab, character.Position, respawnSub); + Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank)); + divingSuit.Combine(oxyTank, user: null); + teamSpecificState.RespawnItems.Add(oxyTank); + } + } + } var characterData = campaign?.GetClientCharacterData(clients[i]); // NOTE: This was where Reaper's tax got applied diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs index 8e07d5c89..3e65ec3d6 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs @@ -46,7 +46,7 @@ namespace Barotrauma.Networking .Aggregate(NetFlags.None, (f1, f2) => f1 | f2); private bool IsFlagRequired(Client c, NetFlags flag) - => NetIdUtils.IdMoreRecent(LastUpdateIdForFlag[flag], c.LastRecvLobbyUpdate); + => NetIdUtils.IdMoreRecent(LastUpdateIdForFlag[flag], c.LastRecvLobbyUpdate) || !c.InitialLobbyUpdateSent; public NetFlags GetRequiredFlags(Client c) => LastUpdateIdForFlag.Keys diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index ebbd2c594..828830e30 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.11.5.0 + 1.12.6.2 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Character override and variant tests/Characters/Crawler/Crawler.xml b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Character override and variant tests/Characters/Crawler/Crawler.xml index f90685787..bb24f0573 100644 --- a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Character override and variant tests/Characters/Crawler/Crawler.xml +++ b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Character override and variant tests/Characters/Crawler/Crawler.xml @@ -45,6 +45,11 @@ + + + + + diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Lighting stress (10000 lights)/Lighting stress (10000 lights).sub b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]Lighting stress (10000 lights)/Lighting stress (10000 lights).sub new file mode 100644 index 0000000000000000000000000000000000000000..282a30b37525495d476c5d7c311c2beeb173cf76 GIT binary patch literal 382364 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�jG&4ED9bvUT9i9IdaQ{gOy3k7 zL-585n_~u0X5C0)@xWQJk{4-FgbMtDQy9%q5~2!x07HvP%NU|JtzfLxfZKo_idOQN zv`_deE7@m3LDi^2zHPZ+L{PP`o8s-)eg;u9`hiah7GCo`!F)JerEMHYEY+4U`(7>c zmVB>)2>+{mGG}KM!};q83*TitndVEodS&!N;}sKmj(ggxSN16>n~eHr?&j|Ng{!hz zlpuWuA+ACsC=|lbJI&a}y2o3Zs$g#}B+j{Ub0^m#Cy=L*;_iY_lr!6(4X>0;&3Ew@FZ=mV5m^u2?l$TMH#~{5* z_fa{8>+$j)rbcZxqc=){@m3~EhK8}ZEV4ooL5R4vyzTY zRwoIB_s;kQO(v&iIy+uHp~>Owo|aTKA=53bnSCqS6C-jvNAV$0s4rO1@N=j&v|L*@ zT4JzjN?3l;*DA#|jER5g&#t_Dr;MUMvNv?!yy@(MP9SX8x68#t22i!ux+?96}FF`*~odeVL9P7#iF=-Pp`f8oEYk9 zbI@l4&QOxQhs2#uyyhk?hG=1!hu#X_f~y6xI<_EH;^cpzj)Rh~QuG9AF)bCut3q7b zqG^3t_~tUM&)+^q0P{s0(ON=Vr`1{g1`w{}%OPt_bc`sDgk580acndUNMYP7Va8IH zMePZ}Uny@^z!yh65I|6NFg%GB-3js3=hso&5bexpfX}2s#}3iX4r-}S`~D}=h9mCgKuPCr7Vt%49nuQ*mYv&xg0ARJ+qVt4#*Igo%Ss|f5u^Vu<5A+%E zKWZx~4Myi3KZmU{zH3V1+%TuZ&vPsGue;2&wx*Tgg+z`*^5rLlYbrPq6inmKvV*&> z*8weko^}pF$YB3h0!5YHO=tcjI#gy>MhX_i$bPEoGOzsn`>J9sC+R>jTXnC#cNtaqin@@4(NAQ4qRuqf z!-_hy^w2=5&Ibjc3A`h>lGB}Nac@WT53}gBn)*1US1(J>aNaV9h_#AVDYTLFORUdg zm`8u@X$?vajcAN-7nOax$vo%+Z%`I$O|kTpfTP|BkpP=tQht`j@x2kN7!VM*hcOSx z*bu#+z#uJ#Op=Tc(v^651|V(!G1m3}6$)f9e;Tyw?k69(*YPa&X8}~DV0r6>&;yf& z*?m2VCOd(2lmuV%2h1xV)M!D5lLoQ>;Al2ce`2E_??pa9sGH&FpVaXda<{^b7CGs$ zDaLe!_0$vG-~aan$S||GT}0j4jkG}Cdz*jRY`Me zZ}mW`p~bh?z@qBYH;~Y51?Os}1`x?R+^JMWdZEMW@QASov}|T!yUG+2#dSR;t|ZPH z^z<3}`Q=oZvndkr>nG@jIr#^bHMG)klH89<;d6h$ucv4Me*H+oQ1APs&Zmocm4Od9 zmhbddcka6m*Q|A})U4GM<~ZRq>_=6*>RUm%T8Nn08Q;N13N>@(_;WSo(%YH@0mDvn z(Im5jZgbWcQkYvp`|ef_sxX>Wga3pMf}F$j@oEHiV|}nPRw9m_Ynp2s28#1&SDfq` zPD}mTOK~ZhcO?WV8aQ!NY;*28A&X%_1z;qTbgp(m?LiB>?j$I6!+M?}c9M}MdN&0e zgMEgzBaD^yl|X!0een#PWVB2KTWz?v>pophQg^XlnbzkVWsYguO8%1Rr?T$Oa~JT) zDh7PFIf+WzI{O;Zi`=p+w-fPeTxyZwVej#M@pwN$FbV0YQwGRHQ$o1S(UmXU%P>Wi z%exhv?i-3crCU<5_*wF8a66Cx5{_TETK(FG)JS;XYtSunR+-9WY z+#+b1?Pa_qo}Snz=r7sCKXu5-eDm2!imU>MrDdpoOLiPrzqL18Ezx?3ZkxQJfDHBV z+ij|sG-sqtYLnkVw6LmUrX0?d9EeVB5|QW3TTd(H?^T74QITai^|jdyE?Y{ zg>v@X(ydUfDA?TFyih<%5jZXK%^`45SHr0ubG3Jfo)g=ZYjFkZ?7d`LBa$Hi&F-YQ zQvjpqF2;gw!(CTg?NTmTLZxz&S4>vv?&7pQRd%(76!xV064=E>v;y&GNvVT!(R)f=BNB1GNV+y=h_LwWVC2HC{pTQ;%btQ+Gi6 zW*CDouZp27R~65zT;$uWeitB0bY8v~{Zj%47^eyMA*vrP zdqfnG{!R>$dUF#-^N@sj>SA!$yUzbLOcKYLFa*FR{>vUEOBx8o`xDor{$17a-z6V= zH}XE0Wn$ey08)oYHMsNuLS0Ak>4i1Tx-SMbuFq5mTlBCCd*)h~c_Y1AA^9~< zb?m+<1LXB(3)p{{eLVU4PqdNo-W&*RB>b$yX(MM=w2`{rK~R3`6_eiT8www^&(8}O zCzti236QN}ESq1SqH;RyjnI7J_$P03Ryu^>7*ZZ9oFv&Be5v{wGExFHq?^mi7)kNf zbdZ!-T!wZXA^8t#jyDYP2tExuX0}Q?hOe-YF>?2_pH?%BGm|~Z%1v#lfXcb>0^Njj zwFwG9qur{$(A)T4#kYh+f0tqFu{s0u`syl!QNdqz;W~NIe=E}Mxxts2ZDv@I`|Q2Z z`2QL7>Et1Eq~PWuZ9??=8-@o2p~MYAkDSd&TU&tewu%R%wIXWjg!PA^aMmA$v*VJ(zA5Vf z5`aowoVl77du*L|5Nh!iAl0}}>HK+OFxp3Q0|`F5#?^;1AU(2hN>iy_RQQ(_SC1M% zi(D$;dN5&55Qu1@T4yHEHz|^Mtur9_$Rv=tE*NMrx)A0PAue!>K0>z(m*G-S-U`E2 zz2fP@;aR&g5}UQV|1p*w>!(edwvP^fia2NkiD2RFe1hXQXQT?M`ma<_SF?owOa=8% ziD3E9qd|(GNci6B# z#820mtxMO*+;4}26R|j%b z_m9g8pz~7sTTD?!Bj;Z^ExzNmPCsm^WU@(GR%=1F<8fkk?+Y_n(19r3^7z3h zN%bsmhM(~;8mz4R0HMLw-G7J%PXyLptAfyAPbt?$%D%7wD8AyP^Fh~vx4;k!kWPZ0 zK;1ij)%C`%p?i0-ZD3URWL9|}BZL^|3Y1-e|3-nA9W>Kz9uk-+V_XgJlUb3D;wLgp z1^cIAkO^^FtF@q%qRd}kfCZrl7rw3(+>RB`SBQHIf>P0W5oOoQfZ!uq3=2o)5l4uT zM@75WQ#Vo=?LwGFUE^4AMB^PPBu|JdN3Si8f>j4*-lT09J zfk(pow1#P17DqYaLD_+B92CtaR%ZL(LqD!S%Z`|nzWNwQn2045E&X-nt=^xBmi`Vc zg+zZa82k@IK#=AA2lS^P8UY$l$!i2w(?Im>ncEnR6g>kzy5!$ecna%JE9z|ZPQSJQ z8YI&ulfNy7UR0fhYGKmKN$gY=%)W$I_FfMhN;A%klZzkcuN*RqeaXUa!j*hE=|?O^ zw#ku^RWRA0XUcHqRST=JhRS#}rbVlD&{02_=Ov*|JbADis>$V4*#mS4>kEdxa`}g@ zy4pn&N%ckj&f=D2%*lLA%LABN2)4Xo%EW)BOCFKNFKqFh>BB3%3|(J($@>8+cTO%x zr27}sQvbTJW!3)(M|Q8W-_WkZWb0f?m{+NzxZsVTqc*Z_tYd-+QPA)SL5Bvokju;Y ztY<_40R7)n#8U4w7dXaM3-m-E+9ZebT0US^b$d-Fb5o@VID@;-0wEg@%R?{Sg&lx| zN-H>u)iNY;#94W`z%*TYRy*|FU^ZK3gIkTMnN9(y{$SQG zVFXA6!9-oh7Ezh5*|fbj2+lyV>w&TuumnlJy0~0fkK%_Ae1Rlv?L@A ziXC2$Vzz~bShOeXokG;*B@`XUtIJyj{ZQrcFMp@ivf2pO{za-o7ecrwU~PApeGdIj>EN=au||^ zk>#Bg7_B#=QPwGtj@-j6l9P{*mQ>hJ61$7}xgfbOgY4 zz{_jZ+-VKw!k4dTH?dh4N$#UWl=9fVOz zA6RKlmxW1A(!RU}`MIj5&WhZWH_oS1q7?Ry-cnPDR@*NlRC;v5>2rscbKoIadlo%| z5d-a9kzTLa@{ZdD6FbsY3$|VARIAwjfU* z(kU{OuHn|og*K9!SSWK~%?ZsPU&R$Jpn4hyasePbr(d`Qcf)ZI?a5L$p6S zk#dCOA7-$>JKtZ0y_Jl5)0L;xJQvE%7s6icbAS zyq@pe`o=lSfr8a6K2NQn?%d*ZN*u@jnK}OSmpv9=G0tRGClfcBtz%r@-pEy2+NGxv z*c1FIFxR3=lfKvai&gxNWp+92AdiVsMnZbZQuBh?$UBu~#;VL$nhm|m$GH@fmb$#@ zt0gN$j?Z+CVN3X6Yve;)fM_ftS^Mh-c-1-RaTAhNlfv#yXkh+lJ;?Sb@o4d;5` zhqRL}9?zKyw#9d!kdRqb)|zv5XbE4H0!5{D%XtSN(JPzwA5{MR&ALx!7YHr?f9&}L zDUOMIK9MrQK3%vx6C1emV4?26lj>vw?jXS-ABK^>0W*K)8}Ki{O6xSX*Xo%QhIl}J zL6&nj0a$`=PH1VpDY8=qr;cGGW5zNGS42Dsta1O_m`;$P z_-Fi;SpRSNE7AX_Www7CRBj4m0fLc)qX^;w!bs0@8}&p9B3<173n(vcv((a9!f^LB zxq`($TP}%fmA!uTns8yWke_J?&b>x^@9SHUuVWos`ntIaqN>7CoR`e6wcf(78mf6# zE5_;&LN|N{t{Tc}slhj|_^{5rf;ue=sv7DwW--fPsaPm;k}ICn4@!FMmn3gne#axv zBy+K%MkF0wlSAr!5orbmF?4L0jTJyR`wIa=#g-w!lJ_^;!Yx$ztR&>q`=>s?Q_D>` zogJs1PcQe(a!d;xHtBgFQgK7ll36H;^6e?n`=|H|4!k`2G_}&m|0C_(fOBKzCYHyJ z)#wXszL&xIKRc(szE|V&e0JMZJ!@OAMdHD6#T0TqV-~vk&ewNsAIwr@o3spvV7u!U zVk!D5JneM+bti*ND(5DA24$i;6WSZ-xcHt+aU804TsUrw zE=-$rC8X(K;y(HyWv$%Xdd3c2zvr|lDxwyje7VP#{FORFXYhz`$`6fZC3%hVgH6hv zAG*N*^)WA06qvei&#LWGTvjktOL%_B4U?EKO|J%}@{`rNxUfpc-+Od2jH@?8x%`EE zZ^I?ATkid=?H(M8@rA=JO{Drt7Sm4hf}NFitjB#uU&a@v$77~gOkOtBw=~_!`0~ki zf5S3+`RKVC!&#LIdB54EpAYGiC6hS{mhJk+TfMiM9Vpd5EON?=71%AOc&-^@4awGp z#)y!JFt0Cm{W-`k;2Jc8@VScqJsJ&suC@|xsos>OCpRGn8N#4J0-r0~AVIM!L)f=< zK35+1E(4z{v{CmtN&#u~sTZ{uWLDqMZSbQ#C;Wj4>2n2GPXRX+BSEq2CU${`s9_?- zuJvOYmOkdC^ZrvvMK8%&W>71bO>}gt5i?>p*t@|m=z{P-Eg>?6MnSb}QAGlznJlsz z4o=eE!p(b+{Urm!zkf7#eg}{-p_jJ7mLa+a6M{Mzioe*FXj|>glm$ zCaqFGO4@oZ^jUjsx~h{9cWk?Qm9+kXW{7X@M{4$neZYiFD9^BQlW?4Mbh@MzBGknJ_^FJn}YZ zaJ?B*9+A=Aa%Jl+o58a1DV-En%lh)`GOt{3Qs{#8(-1Ju8=-Fz5JhU+;jbn-SoD;R z?d6Yag*s%O%&65jx$so9WsuFJ08wtX2m8aL3aM@11RbF}<4hrZJc&?lNfZLc%K8=t`{wwT7WE@X)pUA=fad%aqkB%UrbEKZbk*CoZ9ND2 zf|C~56AUy#v*cn1^%28#r`)IVD*4|mk3>K9hm4g)mVcg?Tw0joQ{N5oZxG1_g5dBl zZ@__H#Okt+TMdHoO$iO8x}Kj6@~$2f(TH_xHKr3#j&D!Yq{#^|>Gv$^sj|0!(Ceu0 zQKPC^1KN=2M{Xw5)wNCa!_KBJ>BJkSc$#;AscJD!^bGBM$xzA_O&c)#-rSjYhF_VF zZ^x>~a$|k$#_?04oL!kGXO=L-Xq#rrtgC~afv>*T{2Uog+~ukl;5h72lbqR?zwfO~ z8_Tz;sp926{<}HTm`lz4N$L-t7_{3YdnleZJUPKOa7&%8Yti)-Lb7Jbg7i z-SlTpoyjouXDT92JndyuwZp4^G;zBX%s?6MZP3D}E^L?L32+JyjQ&6N-UF(stZf^% zAqonjAT~fL(geneNB~igCcTNYu^@^RrH85@qM*`6q*{;;0xBIw5orQSksbs>FM-he zzt0IsPLg?M=KY?xt^ZwTRwip3Qcl@tU-wmR)`v`9FYjLZz5={0=R3QdPVy*UpFWpR z)alGse3n%q?$>SUL1zWt`+I8bZKFe(wz`ToycU-XzuQeSEr%=Xm4wroFKEzCXhY%3 zCwt*=0N`X*w~aA9Eb}7 zmP8)Svk!v!XfI6^a9Z)vfF!Nh8llZ8{n3+mZ{rir^k<}EW}-|u^tXoY_*!X^u@j0{ zc3*scowiTaSL;FB1)dWv0_88tAU8qM;UGHVJ9$1YlZi@S2zJI-9J-)>sf9tl z(Kw)#l|Yg=p&b+~BL*f@u>hxM-;o(aOdEnCKtOXUve7bOH21P0BH(5DeIt*pC;l`Z z292lSE%qZ@Gx5n>2pqx;|?zBfnx=KFcu-_>%mo`+UX=b`w~oGwi7rx>HsI+6(O#MYb0L z`xkJmv$dt;+8;jUkz3mTmq&_HKdBVJ5g5@?= zzlrRffm@d21Tx_mT;o6ot)I$;NH_*UW{3S~A)GDVJOf%4rcF*&Hl|KwYk6posTpSA zLK}~W^Md9KN0WXiS7!1mWP}bwI>cP_s{W)cF1HMh8wUyZj%NG2UrP>jH+xa_Ww`dD zKmp6MTJz-YH^*Frs^l^4v`k73&Ig!JC7Ef@;w3g{O=G!V1dS9BZjJIED|tw&KMvX_QyGEezrYJ?N*tX}d?q8C zpe61dc{&bm?=WOyuryVC+-WXjzp1oG6?zekLtT%XT1?D}@g2N`_08~^nn4Y)gl<-w zXPSH$lGSZE6#!afHf6ExfDf64P z?cr~O0Qf$UmZ9;EEAJEQ&Vckt;q>7BmNb$b`}wx$yA{l@H+wt&2PzdsQzo;+V!oz7i;i`4I}@n4dA&UHGs? z;y|NzXpj-lKZ%Su27gZ$aSXk3i)9m%h+P*6@Z8*PBsWKMM_y@v6^YasTwP$0Olq7B zjgn}Mp$m~rYYae}yOVGFLs}Bxr?dkN7U!F0e)=P|#tCj95$bPW|U?Uk!Y4qcrBnoJN+SvhlB{VIV3yXjN;6Xdf8=N@M7_RT%3kOtR{D+WV zjyE_S>^Pq_WU6Zz>!4j_DIg%UEfw;|!2rmLBwCjpLPatpt#+g##O70S7g1q_&Ixi7 zcP)U*5mSw29xLEw6~zEJ{}5G061NNR7WhCb5~VTxEhr9p?iN!y)Sh~;csr|t{jVo5 zcq|N~bfnvvLXlmS2=xG&K@UVqI}Dg3?1V(o8O^{UB&m-JW6@2yscC;)Xu@VLKjctn zfZC9aSdGa7_EBh>bxt4DRH=MmG7(eule$OKN)7GGn!+z~y<1+SVdt#rpi)vDzWJ`) zP`8P>eCJgCP{dyz=;&3zx4h3Ro|pVbU|%*TY0Ocb@)P!gU0rDpfTfOVLMpU&@B6H} zi%p+S80c68)_YH-Iw#y1_18);<5kpnvD>u!Nw}Wpo3|ks&6As>b&{Qo)3u`CS@zj* zyBO@tt2S>9QRJ#HLQI%Y+%9s$%=u&3x=Z_o(0P+5L=$FQD#+XYOGKCs5aC&!qO&T> zC!TZg{9PQ_6=V4?ap1UJpY|13E2ArgBeyOq#_=^(*y@LyUplGit1vzED6e4tl!(Ek zRB~-Y*VhfMWd~9M^Xe{*Y)QA!ADx-_(NgbL`>S{TX zs`XJhN3QEPpfonlKY1K^ic-QvPD@N!+NyNUTOc6FZAT-YZZZc|bJUr@KtY&g@B-vJz zX{5oK;dZW$%i&W`PbEL{z=2LX{c4y``7d!J{7@s_@-D|rUs0Bp*|?qkDNi)@Ki>LQ z5chsxOnuTw@b7jnG^LX5k_QK$b6j*WEIq!&o?bWxI_=1NtaRFu?+MkxVF3qQUIbE( z@Z%>|Dw87zZIP8pyQS%;pfU+@u!dFh&bn~c2%VcelyYPfO;}U{Fu3Vg$`Q?@07E9V zg2xk;)S7$yOd5dgl=T9~CZ_ezsTYoa-&y@?f6}&sy`V|pfLWi1Q!)yq?V>>1?s_%3 z4|rXWw)-+skONNJ4S>>i*~USq9RZU(-CDfqz|xxDipH<58^a96^Y?$z(rrsi&H0=Y z&G<1AN;z7Rt9rCFb=2$azT1ldV|B{%`-S?p@F289vD~Wp77}jKx%t{58 zDlUG8)zs3^3M;YWyPVQiFBm_#K`R@fa|?pUV~tOl_PW2M_Y#NU-Yd|-vp-VPT^^{6 zcWs5B2A#y2amnv;m3*wuDz06YbP4u}9SaK^g2H57{H9cN@cNQ9aMT=%sX z8NLfGayi+aTmY9H5zHct8l(!5EqwuFr;JRbI43zX$Ut>3F(jl zzzapR@b|EmI|}p&tI&13q!EOvf~6FRQ6~YxedI!lsh3B6Q55j7Bv>#Lm7fTE2yH7z zVZWiD)=(4SX`T)6ev8=Ji}WYLd#LKjEE$kETAFTvDUGJ9`}bo5*Vf@uQKuK5Hs=Uo z&%|h&<+@agUzv+avYT)@RJD*Lml8HncEQ%>k~TB)AviNZ0l@SK{R8A_Sq!zm0j&Pt zi2=baI6?+f-hdPvLnxG7Yz!R>8Kq~)27Mbe9QL7oej`0aP-39VP0Us=Y1Gcq3!kqr z_^dn;+SD%!+T6S&!}P^|Q|C;PX}9nPVsb7kkQGBt;|(xFSa+BI1gO7Yqr3B9j0X*9 z#^_5MuJwL&R%GtckoyNr-CQbas^?&yG`wRMO0hD^E0PsKES1YByz2d4)Y~i6_mqwCTrmLVn?6`g99ezF49KB#N;^f6pvsFzL;bEiaGM(K4$VTPH>M%3RYNliH5%CQ|O$? z-XS6M1nO~9X&SFK6m#u`MQ2;2R#X0Qt^C_DGX5f#nazDg#U?rl9w6(;{F+q^e*sN% zvmSAgyTDaK`-4-7l&QmTdQ%=%He^e|Rrfw-N`C*=dXj*589dpU!5CL(g(BK^;n zIR0wC3jY)DH1Gc+_D_C|O;FgG2!>b4MjUH{_MMHeDJ5>SO5nQzZmm3kGo-|LiT6?* z-SsvIkvT))iK3J#V5b>iH(kEOrT*)Y0VVS9=I|$l|91%3v|s@6EsC2&bPM1*Xn#s# zHw9-fXn*>5XhN8^Lq{g*T_}#nP4h5}L{Fs!(9c5I<-l6}??r)T2io7M zwBKuGwtP_&f5JdQCNkCe+m9RviKj7(Ew8mJ9gGf<7f4Kjqn>iuEkuxmW-PCeKN%jK zzicgsO#T6@GcW@c@dQif8YnT>?l4ocsO{Fed4smu-Y8GiKnPPjne?Ve;bPK<=wqrL z*WQMR+FG(a|AeTTRhLEAhfkw#L!J1HPXrwcR;)PF_N71~>7Db#pb z)fH4MAYwp1(03Ir&~zo>F=)D?tZmY68!7`eT}jaXBKW3xrgOx83bTFsZ)dOp7hecybMO``|a(Y zpQ~xU3mwWn)%xky^Zmgi&AT04XKXBU2OsLirIv?mUJN`-P^Ij?)|TBdHjtE+LKU|o z;~}KPEtpYkG0#J(O+MylZhv`E7?W_Bsj}%jP~z?mma$)o8raxd<#gL*vDS0UQzkF9 z+e^nfM1z;x4DWi{&d`yX$wFGt-j>r?`{k2$@n>llTiZhfL_Z~fFC zis$>8I>+8&pAHW9AsfBjv~59V$LpeVJ)EW6+O=2ArU&d!WlpFAvndNOo3=;6W>ZL^ z@^Sb~!UH`rfeKS+5RKi*fu?;pPE25>a5|T;wVL<4(5-~IPK?+*EvjC_Abh!QUgypr@9*u3kbhu2rxC@|; zD+A&5@h7T@JFd{r-h3(WT1N8X0T;TNng);eUwb~XN3S_{mkAxm3M7C1Rcf{rWsMpx_}+9~k5Nz56c z!eg8)DPt`0=qzJj7|kFuNqAdgy_jS+%(un@N@UXqL2-|*2!=%t=)2WF#s zIgOco#A6FAMLZ$I2hoW@h+8rT^GQW~tk9pPdKE)Y2sGerZPck!og#oKA^h3mJr$h6 zs1AvIrxGCS)B`vtC{=gGv;~VQVV3LP&jSKu-)m!k`jiHw4|SO|BI&?F7(IOuiLw|W z9D2tYnPv16BKziofBkTxCor!@PwF^@M~z7XZ((+jI+&azqM*bjycX>Fcs_)Uq%daUY8pNywG-`BN#$+`xxJ=av3~AWBQ1&B=a?eE6)dp9UcL zAPw^5fzBqvZg-?aa!$!0cG)KQIES6&LEOhT#g5BbR+Cnl?*m5a907%A(RFV>|XgQVE6R+O(i#M2lMr6Z2_dn$58v1 zw7OzCkV`2E^SSC6BuWK$aE6-By#< zHYQj|<8Gma1Qd6Rpa5Ym@VQ_tmO{IepnVkDonR@nJK+NDPGXP?vh|Sk!XR=h#daqf z0J@~8!@W#p5*Q|pDL-<;3VkgjSlGlW;XO;acTA#i*+9`;Caq$+dPRe{slupsL(R4B zCwr^+O@0W8>*~(df8JGQcjBhz(=P*XSsN1KhBs_CIN*=oU@pM*Ay1SPT!)DqcFY%s?L810`qeJ6BM9} z*#ewlJO8-?)Eg*30XCSDA#a2MqkvoqO1lD;gW&Pjslc#Dgd{WQ&sCj&iyZ{KUJej+ z{?9;x1fXPJbPXvzfPZ%(gJU~F5DW8zJ+0*{^Z9@a$$b7liwfkr(+|Nz$8qH43;znk zM}nn?5p{I1d|9RfgY~QbtEs?j4CdLYIP}U{igh!h`o6Rz5P29rx}OGgX%VK!WK>+T z)o3%CQI^SCIl6gAY!A0qvUwJVPEBqqpQ~n!e4iW9T2ovjPrY5<$ol`N!2hEH|2I>C zQYs5rS-f{9KP$vO0+J|8^J%?8xAU{4djk!te*R_Z#Ud8t7;vj7ad)!zc)EB?jAB zs%iinD7Q58PvxM=*K?DxQ6co?SSARoAf`~5*7;eVza^q)|Hpgi#g&`fVgc>irFsWdtx%$y;fi*z?Mu@ zztpK_D(@t}Z3+B&PxDUVF9pteW@clSe$1ziY{CyiN1_g zH2Pvn?H58hwfIfq#Ub;FvW6mSQP+K}7MSKMjt#K6Vzw+h#wR9-?y8+&l=1>48+ge4gOfO zA?sdS<@0(M;-ael)zQXgU6zei7ppPLMb+p!(~c9V9|wWQ;!Wh6RtL1HtYc@HbY|?2 z$5ZhaJkn3>@NvFXk%{^=N3AbxW{aq+rlFODuPscMT65PZr-(YMEEnRORTSAY9N5tk z%UXujfFl_F3Qq8?jF`l$c{;Q+XtZ~KQz`MPOF#R5Xq+nU#&XHE|EijvBdEE$kM(A#H-qX~Pq$bE3sN0|oQs*^Mre*f7=%JBYpz5lzC|;*_NS_5~ z9%OkrHu5=WG3L-p<0_YR>xJf_9S%KZaF4O6AiXi6BciAR+k^{oKqFrNMO;?8p>9sG z&*|tuIOD@+0p@}DcvRlw&}f_YCr*S31YV~voHdlr((gqNiQh!WSW@SQd{cq@ks zpwjDWpcMg@{TCaNke-W2UL`PUg9_S`UBs@#FGg+;%;|!zoCJaIWhy>pCC;96C`3tT zqe|&rEY=SZ{B#^pZ5-TB5CO%I2zZ}}BMs>bl{jz{joW;3Mlxwh9)v)7;Sr@6;Wz7o zU`+3JY;!fIY`}g+=*gBBFN_N~a^r)WJdaiR?rJbEdhE`sVHP+MsxIEc%c41dKU+^0Hg1fB$NcW2fv!ro} z8HvelFJ>ii=aXWjlkB`NMwl(IS!%#;l9@OmHbbaWnuQKpy6ZxQ-qR{q9oC+u6Zp&} zmvam*mm-(2P7?v!i(MUd=WADZw!bPI#W#h!Y)ff2YB-p9a&b1tVU_kplC$n5M^8l| zT9JNMeudqKSNO2~3o*Y7w7gFaRP`Yn+<-w4F?^YgOdw1aF$_tG_s1+CB8GWKctt?O zFaqq8%T?M(BLN0!SPL&M@TDwf&oWMs6|3EDS7}wgBwA)11nio zFdYauT%`k555AKs`@t^A#*%ulV^0H&)8jiO)Q8liLT|#(W=(N)ON0C_Vw^+(hTlj? zL&7K!{o)7HU}gU>iL$@+FO>b)kq277&OTDAKqTWH~F2QbeD0~UnFBdnF z?}^P($$(d#J4+&8h84c){KOYD&l-Z#HGsr12cv7-gf+ zZ5O#iRCXZfl$Cr*1w5A9(IkU`YfQc=f&+SO{4}ZR_fR{Ga_Oxo{cKNdQ)I+2{JVk4 zi5U?wO!y+0yg_WE5k&>h!M`%=Xka4$+^hpBc({-Xp4ndto{41z55nvT)8wHC@!&{b zVk1A&gkSv6(Y~>@q}ca^6X(p#-#`8E_OUiWC1cuVaxwRHor$je4$bQuL$j`M*T3L3 zee*PQ!1l&d{9dfG2emm5J`@N`!S?a3t6W5k7dg`vtTidR` zx6eH~WnXfI_xL`0?VNZTkTCqM=tJQ@b%EON5ZyB1 z%G721qUZfwVpm*Qj;m9-Pd(h;G{tx^UjS}INi7M)T!xRbml=ka8<{p($1<~eYk;3f z^`$h0W+r<3|6I~nj0Wh_=GhBg)5Gdpz`zEC?O}uoLn=uiXES^>3&NMGtQ)>TjIXl_ zL|Ou+?w(qSgpGjza5=mO;ucw4?g3$NK$s?KHfph~YagWXotxVX_>_5e96?q}#P}w5 zfVYiy!7UeV7$q9(?$m(`0dO>B`v?ubf7HE!vt&maK+~ z=Zh~cr3ML=eT3H7ez7wd3blhV1eNhJ3|LWG=fc)l$zY^~mGCPP%lRlsoqzi8K?th@ zH<|bXyX!803iw~Vq>qBKx=N5Dk!(pO#RLZ~eJzK-bjk<0nl#} zfE?GM)l>(@o02kb*Sg0)PIIwp-KntQ^vRSxswEQn*rk13`S#zq4d?TKFBI_mpb)Ss zw+5ciWqSW_c|u_V{qK;$>`~P_N;e~un!N7JJ~?ff7S((ACAAkTkHhMdbujDu-|Yzn zEtkem;xP{tJrI3%36!+9=|ea~e8nUS;Y(Rec}_U03d-#iHqF3@h<-4rj~_8H=pUGL zKC1hLJGyDW;Z5Ca>26`8KHHk`c)lya^+P&&K_BTW6S@=e8^sK?Ex&yYvV1Er-q;X+ zF`+ACeLz!1T}$8>TuQUsryGBv`=&$&i=S8K#2HgI{`v!!h*bH|FUnquQ0T6K)=3a< zL}-Cw0C`+rrSu`TAHb4m>}MpFls?^6dK)`P7Rn?7g)*Im*S#bU zP{;>GG8lw1S%Ofe@`kTnA*}|>&vd8f$ml5%K>sJX0FL-RG_rH;;? z6jm{6T6|YMnUsouEGp*z)vvHsNl09){Gz}+)bQ=2q0myN0n@FP z{NvEh_REF|6P-q37|{Hb*|N<3A(YBA<|FYATcvDK$OLfqa-STyT?BBry(*zL<$e@N zWCw+Op}D}RxgYjamH(CNMX`l6bH#5 zKnGxOE%KFw!F8mAVs2quND(7;3tqDFAZ5gG066>AkZN)OX4FfLUPiVg0lV=^NxGnj z3PA)+w2RlpmV;fk$R$SH0cn}*bQh#Jx>lExQ*f3Nvqpb^K`FxcKSw006ZjwHf)D;z za>46h%=x#-VAv{JHD}sIG5QG@MvXa>fVCd@0uFH@8|1U&HvTUcj{W_Dvm4@&j!vt2xi z!sKSiXk&ukOec0t3`U4YXq|eXa%$|LZiuVlfW(KUopUF-=~_V)-0bv>8SkBW%Q8u{ zvTLvloC|aeRlFrea`UpZ8LQP>1b6mueamPsd!BJ!-&|aO=ml4u)?lHEVI#Zg2Im81XO( zRR3fBFQGzMljU@}NCUf-+RWA{JT7}H$W@5FumctXzuJBVRO7g~zDK>4Em+T_Y`D#L zxhn0;eFPQ)e}II*9?L@D1|S4(A_##sSB1dt&RjqUj5pgd8(cUAm89PSA#k-J%gyY| z?RS0&fm4AH_&T`|c%mbSCPNqqfh{-?LSP;s1lIpkA+W{bC<`nE))|DW(Qqw~WzF%~ z-y(j{<;yV-kmLX4FLVGCZ^Wc*4dfeCtmbGjvt3oRczs* z^(s~GxR>+o;FuFCFRonI+U*8HB3>vsl&$1$hak!_>N-0&Va*G!+gBxH4CHf_Dxi2N z7*fy}iZ#pHn00U=b*0iqsCn)ACWY`|5k~vd?h$|c<+`9@8m0P}ZP9i_)huvLd}Npu zhFf+AVwnKd3v-nz6!m6)m)$P%Czg#nlq@A{DXEdxQ_3osqm)%(tUvkb6`7x&9;ysi zIgs2z2o*KKMFng_^&sw0+SOhA_gX{8%fU(*$y|2j|L;yOGRr$6FC5-Lzcoh7f9 zjb+@KiH+fyx2+EUG+%CR%wE4#@~C#%#}D6(uh^L+J#C{qZz8O1rM{=2z`Xn=_OCo9 zA}ZL^e(R;_7+0QXe7(De6RaJMJ{?)@E4`d80so5j9Yp;beyaaex1WL3E&CTnLPiR9eG0V3*jI>QX$*vhqY9 zh!!`9%nv2$+h)q%rSv~9fAeXojj7NZZ9`TZ}!^G$Q65b zGoP4$Zm`j&{@s`JR6})>JOcNo5TwGg1@}Eay))xoL+cxs^=ch`R2Zxh-ZLr(gOM3Si`?$LHuT{~ag~Ka+#k*&T`C71vz4Y3QVX)u;*vZ(11^U9LQH=D zJ0~aD9HrAZ5^Ts_Tpm#pRMtQC_1>($)8wR<=g0KRKUX4q8D|cf?@(}z5n2=udIXk4 zsf^Pk5gGixgf)?lybo0+A|yj^_G!Z5fnw!1q9HC0t*d#iY62n(@h3Bc^U@Mg|cG|4Mb2-oT5#E z^7}w}?c(G!ya(_1$E{>&Fw!z#EMk8_7NYT_2pFh(dVzt;tr0d*$vw<$wM>nVFRRJP z)VZjA^GadknY)un|J2H|sd{j6Af&*ej~)CnLHrfw8N1JZJ{JmKEuX_YE9WvOVV=Za zLR`^s99^-W@#`CK0LO})gi7*pb!SOBD;jjlBR348vAZuJy$_&n3kGkH4z~G$*1^aE zByjcYN1tOQ8)To^Z>$dNOTP^1%ccbIon`SKDdsYK=~`Eg5+wS8zC(mDiIGW4MH|xjQ7l&HDpN?an0Y`cfrEik0!L5qxa6|y zjMRMPlTD&xgAYg#2gL)j6;T;ojve74iBKf$AnOpDv`ZL}uq4(OL9+5O{flJX^s>F< z|7ztkg=NVncGnvJa@Y2(xNE06ZVRy@9}F^?EgFVgw714b8gJ^~{5Nk5%k~kP^@Iok zrbsA4fbVYKza~dzBr$zuDQ>*cz0+Ta3Wki!1w*l!ndwykOmeNNs^sDNLG*|+bKJJT z$mH5jLnnN~66%JvQXc7_&loFiAMMT)`-IOwR%9%YVmviI`mXx!J-oUI$Wk&|cXb*HI5pKDe!|aYM@5yxwAwo(Ok+ZiJM`DF-cPnIA9$yu1 zEz=sH`|1KN8@g0t-|+pIjUsAG^QY;!@r%TXNId)#Yl}m>KxlhhXIaD272L2x^M|zK zPuiG!?Y3E)aXY*)*z%cb@Z=M!lkd0jmI6IxOV9%qP6f3enURZ$?|Dn*O{x+Zsp!0B zm`{qFP?Qf0_j5)6=q`+#*Emu1H3q+PlEs<2?R$n~Z<}CS>q9-X%|NhPY(Y~D=;B)E zs^%b4nW8)E`MdC>;QoxtvGJ?T`@YAs(TeogrDf!c%RSOo(w3P%(wK54wmR2*(%*&= zKZu^zzNs7N%i2({%D8h&m)5?Yw{Je^x|;lk?7btJZ6Nt+j(14}5$ ztuDQYv{-g`cK1EjgW=d$i`z&ieK1rmKdGG~7vk5F6` zI6|tC6pjU&F_jKMHp1V_C%Z5p;ygZkVMiX@XbSp7sfl5>^w6-nD<HOc{ae}nRa`)br zVFr+Kbuj@Bo=KnmcLres;V_zpR?1^yDeLfsc{OmeE}uhd*C= zP`u6O0P9)QeS5xGwpb3_+byJrFNFj5Boir0hAs~oj9BMWWTRqmF&;qMHHh?WeHCE7 z^jh?KhD$}doYq{mfQen??AWADdWLD_o8j-lR=6Kk!?*q3%-DXgk@mY-su8XhYS5$%pt8ZS+iM7PUKj0sT}sEYV_v?PxwM16gX)k6}c zOlyw+#_V518j@7jBBR8DRLrgCv0@RKVnlQlG+AS0&VifEJiw~mew&HpA!1#b-Z>>^ zkgNhQgUsgg#|eUYRR{4ERyyICO~rQYfF}(%IoMcukjb@A%&dE6 z@&2(K5S-MScFH2A)KW82<7V(1xuJUQ_OT*y+>MN6|9IKf&O;9ujHbuR%ZxMR4oYMe za+Hc&+UHM<#$49PZYb{@wzy{1#kd?{_LE6OM(3(Y zggBNIx5)33XkQJ=m0P%)e1I)&aWi5NG=s_Tjl7K%(Q;1&WZld4Chm)RFS1s-o6hp7 z#7E+`DZG(iw_@`)oko<6c%#4|0~P7z+`SS1U?b^uZ?zsRMYT$Cz-6GoJhw19vKLZ= zUc8EW7o;lLEqD5*KM0e?9%46U5b-WyQt94~UwpO`L9&CMyd^DXSXD`4lhzm|AMiOf ze%g;@17BGTn|Jsoa=Kwu={|^e@jQb3C<PJ}PIiE8KdHyHzr0;%0lUK6V3X~f%d|AcmIHD6C?6U*iCp0vEqRJ%r>hhIAyz?$G%!Fh;bo#blg_C51 z&gYq^@;!(v4%|<(9?n}Id!pp<{n>8J(X;t`we=l@&Q`?R5+=w?(+yjAj8rn^j5fr+ z`ijnvJUe{uxm8ADW%G?Ry*lo?rsyLN#s>mMW-jA`YzO$_Xm&rY^lvb{FHw-_WE*-F zA0UeIALQ`t(PeYxdm8PXhZ=UdkA`MP^@`Lmv+czWX}H$ezGHN$PVMC$D5H}_<}o#k zT|JQ(@ok~HVjM(wc`C`Rt~_q*RH~Bw*QrdHc6B)Eirq-IZdNFePqY7!<=TXb8&1pP zPpP>&T30@mZZ&PMWzX~?@k*%q)un;zrTo#xj>Ay5(!?=EEzc?;^|jcHoWa1UdF8&d z{?3&(_wUc%I-|ImDcvMpkZu4+2fCFyiL2pq=xY{kD0iJVn!%t{UCItv=-c+$bov=t zj1|>Sg<`WAUn!08m5h%R6#(~Qt3zJ!pkl-q2el;cY+LUj@tf(LtluhZ(f4wwb-Z^u zEq-D)E@g9>nxBnjZak965|}RcLpk#6hqSr&xfRMPer;{9=T0a;gy~4?51HVhqkIQ8 zfCbd{hw-1*E!b+HoFq?A4o)i9jb4+EC>i;ZGu;>Ozi>cVGM?35vs?Ow?O-m=iR7nk zrs1+){LSMrX}s6OgY4eou%gpS`Hv-+Y^R5nux0$Z1%d1fb>cNlwET+!)#bNcTB{{K zXQ$eI%(MYf8qM7gv=%Ouh!h0mO-#rc4QpLtF5Swvdn}X1-9=<)o0%Qkwm|OI6zmUT7I;LLECw zuTLNn+3%{Y8LIx|ECp@{fqY6@jtkD7J~ceTd^_Vy_uDt! zn^cS?G(fGIFgJQ_=(ku>q={NnE3s9ju+m49SknRi(N+BJ9@}gQ>!S!ljAu>VVQoKp zc9ShUZZ9`^C5-U6U1kuGhS#`(Pe#6KVhh)j-=6sJ?GH$1EO0q90g$&9aZ`n-bn(Gd z3R61Uge---o@%5tvXKEiOT-p#0@VEKL;+&ujtl$I7q^g*hJ;(iE+iKO&zWLgNa4~t zXdQQB>)ktFF1@XpM8z<{Kqp_?Ne zvbjN^ayP5x#bbz6%vxn?MDtB+U+=Db}xkV1LU>Q#z zF1X@SJpW{dWlXf&?knzDTU_K~@y$ktrz(HZ4pBZ%b(xMkDf4Lmm>*C}h5LKI3I#dZ>3b~LBK4imt(9zBOlIt1s_ zRE6` znh)e3&3y5jFk|=qPc16X_R?6Ly=2bwb*o3=Ru2xVy)(SQ$iF)7cBI}fvRY=PaTbg> znKm5%ZOSiFO%^d)x2a4|)}@R@pSwpgWN)c*Rjhl58cMLJ6ZxQidf_w&+QO;Y`wMsL zqMY3~^M&We0g02*y0ydN6Fox%*DM;v6B#a{ZfX9yj)l)Ut; zJ{hfrc8^G;6}cV}V|nYth)i>GOOwD-?xl;}Q^VqN0kfmI0&z{Ii1q2*uk~sD^7?c$ z10!Oq6?99}_P2YrNiy$rBE0Z;ooEtV_b|cPiMh9aMCI8BIjY}jO40e+Kj{Jqiw<^i zk+>g%OdDq>qdOQF@0iHe&-SK?rCzkq z*96Y5%8a^zZuyM7@dQq9<{bPf#hr$Ecit_pK3+elc|7QsDhc@SD z!^)0)#(eF4VDWKZJ5t}F)&6Q@v(xCr!oe)TqS%^Tnj>OPqbc+3Afq40ZR zIymeR?H9{;=$nO1Q6ck&t5xPp8Y~uC*oRvz0BXE8J9jq1O+#!X{;M}TY9ZnGPLr96 z9}iz=rYX8=gkJ7eM^n!!<-6ms&AY}eJaNNP$+>A03cS^ZLr3*f-*!mw=I!gL7g#u( zxYv>Sk!}y#AunS@EmCG(cWP z*h3t~y8+I?$cT48C7CXust?;?$g{Ls_}MPGb;t(mF6g!*e)oV1P@u>(P{PrKoEF@o z25qpa!Qz%jc#s=Zr$W6%R+FGorwr@&jquy8yf@Q^iS^FdT4aThO0to*l!MGdG58qt zIT9|q0#$T$5Jets$wvOtx%DJ}0T+!IpOG+-pkWfICC3($q!z+2cJV}hWkOx`u@17W z8eB@Aay*YT2mf_HJs8SMchq}*BR||sUzM{FpDQLLoHlyJAg5cW zYpX+=AT|meQTDO%6PsC%<;{%wvHLed+H&SN75j_FKIFb`{M5I@)}ZuZrPqF8!W1g<5o{;mabOM&@r9l{s5C9HPtA?$a_`HbAQCNX3NK)(L1GZ z*>(5gd>X#d%)gX=ctkeMXJ3Sc^L*Ter-GCCOvlp(GcOHzd5v0|6<5(F?xBYeGd{4L zF(+JUE;!QFq}0{IeB#lADB=yQS%a|d5nrK21I_E3&en|)7m_lP5dz$;@tfHF@ zW;Okb(km8fy5($whxF0m2fb4aPB)1-q4;yXRL*?vJ2zP%xPaRmDZpANeyOJDRNGaX z>G>l}r(JT&mC#j7f#RHvJt(v5v5+J;&Q#0nN6~?K)ZqS@kr~-MocQ^v7_p$EL4(#2 zJQ9ToRf2iusI)<|{OMVj0KMSLwKoi?LRj;swOtr8bW^7M^Ga(jD978V)|;nR8=Kj- ztj}%~^tm;)U-H(-46R`pm+N%v*uX1;tL58T${INbVwA7xHZF`fuM}A7)|9o#vYLA> zizMaaS!}01Rm*BH?d;8X)zMD7F3mW@HU5b(KVIs-Fs4YEV__9^GDIwDzP6f--^DP$m`zo)(YYQcsV@?+VJ3OiLx(tFz3s077wy}8Q| z3FRG<@-?mzPW{)DKcroyin6_PgxR0|+}Sk~XFhz~yuZI^ME2L1j~`{wBTEX` za$k+f6fk*J?u>5x5}n(GFPP3c)imZ>SdkK$e?U&lv|nrI)2FpFYV0G-1&4gbgmivW zU+NLtIZHb?ZBc3Gs{UzGIAy}P&MB5{=t(fHwOy#g{Bgx4#R`U~ug+Naqdx!?6D$Np zEF*hP6+H+#1F)edBfiU4HcB?ic7riQjz9ovPW08L?L6CKT@BWOIyswE?JgjxmR`5I z0YDS%M^BxIOb{@cI_JQY&7k5Sic0=;g+YV^{I8P_Jj^v~?>GvoXH&|1+aI6m=EGn5 zyoU#T0Aho{j8nrEN;tINj~GP4YjZ{HD{*h6ZWJoWS*GsvF6o0DagOcBGcLb?RKhz! z%j`voRw?oRXQ1eJWq755)k<9p#)#HmNRTQ7NpY%39LEG`1G2$rp8n^dC3EYam+Yok zA`~YRCxasK-ydY9^yjgKc_Wl7+XwNn3Vw)m02okW*sO$*QotD{rw(WF*pR9{5(UWp%+Dmei2awWh{vESwG~9T2 zWsw-|*1zz_HWE=>T+~-1Y>eK+;;kN8WB_!ZInTb3<`U&BM#NvmGX!QmnGY1VBwh*u zc}ll9UY({Cfp`JVq%Bp>LQDz6iqUTi{ZBOz*6U%m;6ZcrzVF4qT;aVM3 zq+Zb7$eG~WxAT3D@&bA;yHWRpviekSd6wOP@l>X4jgx3|_Dk8cF0`XTf58CEj(`@i zf5nclAlZ?>MxPoxB)1L*VOx35s0eKv_@Wt%q2*0zGP3C~VQZtBJ&t00W2UzD*%`|S z98>1{t`>oWG27=4l$GM&D|p;>ao#R&IJg7opg_s{ZXbdW%pxNMso;wDo4~K52OnM$ zYn(D)u-@aTmp{^VCgMog<&2seOZYKmff-yyQUt?pMxsq)TVS3)iXBwFNtkIsgZt@$ zV$6ta)bsO+6W@*I9>q`m&|EHy7hNJS`@p~TYlI^#UqOdgg z#n`*}t#X5PYNfCai+I6#uDf%#!TRSXSL)&ib!$8W5|w1bG(&A}?_y)K^;MsCV%(cQ z_gib^q(-I2o2oIXv7C|qbcK|?KA-+r!KPf;&~D8KlXQmj{Bq}VCLGwPFxVT3+;!Qp zH#08urJoQT-cfQb2lc7d{ZaMVKV}ex@kjYxrv4K(-04Y!F4Oq|zc{?(n*;NFol2JP z;H%soZ`7bO_KNvKlFN4X?kPOOQ8I+_#OWI>DO%Ml0Mx*OmI^&cjO?I2{{+=vEu*wi z8nFS`Fy$u`NDL2XB;%s)Pm1FooIqd+AX8`S<%mHp?V*B#EbDiqpoD3Ikp(9xDe|(C zA~<8NEE-UOz_5`-?-8(8am!A`bxhEeoFdWE5YU=k36Wj`T<0(@!#oQ@3gRIEg)S&Y zP7k0PGypYIq#7LpDjI)=tYi_89cbFNs?J#Xw2u#X5n%%aK=Xi-NQnAuG6k8D=lVBD zWC!ED-`L4?AEKq6qzWPU_g?ZL`Mm^aD7C82f@VPI*atX$CPBgg)B^?9;ejYfg@lkL z!EdcfQH6Dj^j+ZBen+57==6akUk50NyDUSd!^cmBL&_2U(z^d9l~8g~=S39qA-DS? z%8Gj?ivKKX%|zl`b3L2Bya#FV`dZw{lcV~+hOf@5HUUXR97oR#>s?XhN@6{Q*SdvS zPN)0^YVn~TnrciP)jHef%13&FgR0B}&b!?5l<{}QjyMf;Di@_$rv?|duE&=#Psq#h zO5j2{pG;hB%bBRTu@AF@)=&`3TgYoG8a^o`u~h57glXyD%^*p<0cx1Plv*qVA}E;t z1LeDW|EzqcPAK0^la=op|KG}YZe-=VOiJZD(0KXl|L-7N87|P*Ry^~FAJ^8pk4D9` z`bAM^{=j~86?%7JCr`<#2W{I8%lrluFM3bo$9deH^XM;4?d6oI#6ot;S|jnTbmC?1 zONK`}S;8e|lT@rf@GP7V?5caZR8&>>Jz{CExy!=%R=Kpx>KSQo-@UF3-hQ`W8Z=dL zEp-c-mB6KbGi)e!waT9h-Tt8fog|UaeRkoxU9J<3&XvLLrYYS`lP7D8hB?^6AVTi; zZlFLAEabS`aRge@1K4v4|MBfv0MFiYoP^bFK%{_a+b!)2Zg>l0+j#&@u>a+kH2^~q zBQ5{{9)VgGIo^_HHTMM455R8STTy_x&Y4_>G!Kht4%9MRh|oqYYe4=cVc3+Hig{SL zDV7p|!>f8y;Hbp+QGze1Q&%W}k13vNL=GMeOukVZq(0^c!BQeo$F6pmC?oA>4YQ7a zYmiYzACQaxgffI7S8X)X5(f^(gpF%8s{R&b=ob0)IM(=`Z-9g!Vgrny09J#vVFMuGZXgwDG%jg&zUpg=h}l92 zxB>Z^wr|Z6=;*N8$$@eHs`-B0xt8@lYrGH}v={f|=x*FuM~t}$=uGS>a(``(ngxP0 z^I#H7BRCycuz7TwN!f9|Gnj$Y2Z$(7=+h41BFJ~{&5|6BVRw>6<&i1hNLyr93{;Kz z2bgWo(*GvR7G4QswpV{&v|0-cjgZ0#wDbAb3a6(*`sp4u+=IFPJHnZa)aHT*kCw7J zY4vn-!QQ*6<&1s{#tZI85W+s1Qs24csYA!4DO1m z5EdN|r?Iau=4kBdC1^N-rx9p4w>|p{k&=P0c7Ck3Nf|<;lto#igrIn0_XCYHS_-H{ zNR-4hJdPab0vTw!FaLazP5(nx>?)I}zE3NADB6%q2i4pnVHTlb*C_rhM=794Tj-%d z&&X)v$ey^;UABLL*qoH650r}c+z3eOE0ojX=B$jb$UgbVhaOfkd2RhgCf4+zU(V>; zPc%l?KbE=lbETlX9j`dXC*|lVv>3$s3MiR;)>+_>{RlA8uYIqZIIa`QGPU_CflfTv zci^W}yLUR4zQEDNxz^is_qjI96Q#3#0gYO=5>9P$pe#w)o^JqXXN7fRzq_(+KfU$8 z8?gZ{Z4U5uNR;9hvI+Y9rAe<^k#o$b=&LZa1Rr z1*4)u0ErO=DERj>khCs4w7M+8EeIeQ^sII5LY2aNek9q?aPx)c&m=$>@`RLL*$T}Socd)HF& zfWeQ(HU{EK*!KnRYMN0A`u?{CSnE4T9z1T2e(6@iOKRV@U(>I1sWr2|+L6IXGbd3= zZ>Te8f5AD=m+ut$7S&`b$HdmzMTF%T*Gzx|XQ>##0*vp;hn2xH6gQ2^2J*@?+HgzaDF5d=5DFgd_=$J!#mnCj%UNxDME{ zM+-Uj6iqW4mmK}fFS{Cc8|LL|pvUNO)9tyr^W`0*b7HQ|uOadvmL=+|2iE=jw$pjO zX1{&n0CPWB&GFTDrTJs-zZ?4)^zhJ)SUN#bgI>OkOzRHPFFL*`N;@t2LvsGGLI1)yK!qom34l}e>bjo{=0?8%XI0!jN7~^ALfNz zlAlb@x7`{Wh_R6MX9~>@@`&cL$q(E#UnErCIj^wuYwZ%+$7Au6_+sc-Yg^#kg^HUC zI>*`iWpX;Z9POsPGj*?6T~N20+`wbS29)4HZs}DHbcq1AZDtIHDhPlGsQ074&jL|w zEFX0sHxdl4DtX)hrP$9Fe7aBO+-d2*$-05%Y)(nx&`2hYk2DZKg8wCe2b_hW;#UX< zN?6=8PG)C2m-y?ZxpMOae+c+6F^CleFmi>|fbq{O@Kx^+Et+8tNxVOue8J1kW6}C zQHEvM0}wMv_lS;EGW2;e`Xs_s*bcDxj6`<1IVu~leT%*%!|+c2?n@#>gjKL#4pFcw zyrLxBWSyW054|ZJj}b(az1+;z;R7+!J4jeEy|XUoXhmjrAhv+n(v~wyRE$J9{38Lg zamIh2W}7Y5lO$`r7m#%qxbNsu>v)hGs7l<;6@86NM5utOec{d<9{IZIs0~9^wgQM6?4g5m#y?3H$pYmyzvd|aikhPEn-*RpBsL#BLGtRTv}H8 zd?qM;en%*Ml*yGol919TjzsD6f0*sxgxSj*tTufd+`#xwyusdGjxwT`g1-X{j5C&jtaq)%H((xJ zfom{!g9sd7)Jr4)gLIa%pbDpsLYiP<=mvzD{~3_&A>aj-@PCtKgDms7sVt;)kie1k zQa0U>QvitW43tEb|8~d*+E4)>{@-NTV4CiM5>j3Oa5eV~DcAzA9K7q5ACe>#+p`V= zM@C11Bl|Z%w%gX#bxQ-0)GGIP8cdz@ z(NDnCxnUT!Jav|9I;$n=^U)AId2G|~bhYI)A1D~h4GI-T8fuB>C?1*l$igZ&=~p!<98aX7?Y^NG_@=38yXD^trZ8n~v_9+#D+SW9DE&VNY<}8ho?9 zZJA?47MuT|Rm6#7wVpdn$}~K*xt<5M3jZd+n!PmjBKwn4mJ>G z)tNkD=;T}=m#lEO|5%FKd3vBhD0tAERPR_yszF%WY8ot)>FB%v4vl3rt92kO9 zRuuNcyO%#<&MwPP`R8KE@}l({k*UbGq_xrxj^Stlx|C!Hc?zzv#HP>=p=k-0l z$MHSB!~^tqd*{>h&e&+M%$E=b4W;XdU5UiVw+!PSnn&;%LbK5Ax+nIkOyOsqVk_ZwPp}^3k#s?ndZ)z~-p-sb8fvY~EWsD_5IM-yJw6W9?t_|rWOzN$M?tNFzWNNEDy*C6r z0^IL>2BjL8f1x}AM4#xvY2$n@5gI>U%LiVwZDwULF6M4Wa(>?^7ea=w1P@=~ zrmYL9s@MOlkom%27cwiS{Y&gqQcq-i7g*Ds@$525@IL(BRjVvVZ2e91M@$$mWi@l< z=ljY&8QwzqVEWoT%3}aNnCc5Ym~f@YzzUEUW_kH+MekERyUl>^feD`!9&gXFQy={q zqA%T%I%{&je&meOf7CkVA9-Nz^38esHeq$p4^U0=Z71Yy;tdL}I*to(0aa}v00a?U zG#kqXA?O(&5ZkhaKyLH`BeVo|=sYDykV71w48 z*LxKF+eAK}j%A)EM;-2#n}kq-pR_7Vyw$%Lti796 z|1bJ?{(ULrHT|Uf)As&KM(-2eU(%U(x8kU`E9*_S^vl<^(GE$*DyG@5b3(jym>_e9 zw9EEEYWqkP^jDTD=*M&)ab0Tsxa#OrP(gp_K5ZeXf_`(LAF#7rznWBj!AUB=SXGHA zzc8XGzo3W9FJuM05@g%2VINP*WX;ZAl_6RfM`)cxR7ydx zf!*afSnwey)#U;<%u1-*X%a48_PO5op=e^K!m`B2DF& zqK^^%4*)g~abVuzu<&&FZ{anXZNO@TRu#&BEVEqzH`KaGen$5|0N?z;V}(N-_yQt^ z1$%Di@}GlkL1Y;)CE2(h8Ta?nPUnZ&EtZ{THDWCv>MySYusT_(vJ zcPF?bunI|GIZ3S^ZBCRL4x|-9$s1vw>R*r7NI3BRS5#FUY>|C|n)7z-SzmH4>eCz#JC?0&>svug$Ym78!Chgd{n1Icy;hSNsbT|Reqnb)M$Zv; zs#*OvT`%cu?aI`r+7AZFHLJMfH}=;rSc~BdV3=W4Lvgl0_0K)(zi2YRGcu)?4@AbsvNYiX#yZ zO=ka0b*p5s8C=X7?-CE&U6Au>!Oy8vDlunJ?Yiie@%8j$jh9D;=~mWzF~Z# zcf1)$D&x})O5K5^vKKog`J`aePdAsUtTm!5nP`@lR}|RXM!Vpf*}jg;gatcq3rQ*)AxY(K09=zH zNoD8C;AplX24Jp$#D2vjNo5xAlPk$?lecv?ps*kQ@fB}3hG~?M$rkZfRjN1*A<#h? zwlNvZ?%)BRXL=$WA&-xl7+_;krGT@0bCN7!N_rGC%lC5NCD69c@Tdj~{S~g32Bsu0 zQA7tg65xewiXu9&;$gn|v}_Z|!Y#1({BC(nD5NMHR7K4qlgglQkY(_vP4aGr`$JGo z{}L?uObts4Go^5toFhDq2|vFOGu>OK<#Y)poM}=rLjK;S9C?6q;K*DkgqGkCB*(~^n)Tvqprf^*HrTPrq77`B zVXKHd+#r(l0X{n&Jm=po-n=jk3!n6RxhRJd(&$%eqmRUq0>jRtW7V>_k>@DYAiRas zcaf!s@MUwMdVwZE=_JLD8BNiU`)=Y0AE_uZrBu&aOHe8@Cp}W1`mIMby5=;Y6WEA$ z;+)=Ov_9xf>!Rbyg70Q7M%84Ez#O^9N;c*jrWcgI6*E7gkw?D3;jYCGK1MpRb1`t4 z0E5ju6dWXt7BN#CFQx4!nEk4hHFVHDai%5XPl}TZ6q%dqX%U(+=(}gFTPTcA0#cvP zrq@a$qYE|pUT*xT+9i}Elj+(J?K7n4Y+WI}wCV-xQvXMKT*c3_QEwV&+X7Nw&HCLy zX3}>_g!Sc@^{^p+Rfi^ckWDPa6%kwlLNC>I){nw<6FhCoc!BGtqOigD4&>YDMuuy2WX^N>o z-Id;dyQWHGcR!ygLrpa{Wp7a}u}Lb%SjqP_0ya9W3wI1+wE}`n=gn1oxv6~BiHSgv zc`8~?R^P*gB*^T$w4!UjK+)v-rYA;sw^wTl$$aP3sxG{fEuJPw&r&w&h)FZ?P<;CJ z;aiRg!P#jO?dG(q0<*#4OGeJZ!mV{U<2WwaTbfRg-bXuu z?MZCsO||1UVcV05K3-sZQY~b29*I;WAw{pk|i^Ab@D*jTfGu7|2rmUZYf16L1f=) z37)nhDZQz#xjQ!Xj44+D*>@$d^=V9t>J6J=_6?TaWmy@jA<4n^mLBQr%Ujw!=GhDG zC94g7_?jjxGkZQUy0@X&o2cN+2&(9eZw9n=kbF;yIYWBXO(&;`$}vr>!1qL_qI$%x z=YpKrYzo5nB-7RMD~0a~R=j5>Us4b0d(ycQl4PDmNix;srv>rWOym%6y#!XGr!W6D zg?Htc3GM+E?@C@SD;De}6cA&&7CFS`qK(Fh(@#W=ddXobB;Fi*iaTb7yuHD7zJR~? zm1-Fs*kx&a{?PNh=tuod@LTs}LF2%mUudgqgH5b;Ghzc<4d%0QIHN17Nip4Asnw)U zMgj-nb!}H#6ivu^pPGpu+s7-Gg1gu@jl`+J-(Qjr33N?z-(dzc^lIPHr|L*vX;#I{26~bO^2W!USxVpw(d)8>1e-RrSN+N zL;931exs!M>4qpm#p}CjjmJ&kn=c9q^``gD)9NSVV=F%tY%=VCVm(=Zo0Ib#NkV$_ zep-FGE#6>as)wh~I3&;BS2b0rYRuCjW|r1%b5R|s+ZI#5jkm_kU6L*7JKKUX_RK;z z9&lph@LzIJoE$tFdUh=$JJ7i%7-&jgp^PixQ5Q`RbFfB2PTx&iCkCe?le8DK4Z+8QL3tcB`@Pq(+kvFZPSa8 zLG~dt*rs!9jel5l)HYz#`M^X+$JcTLY}0u|tDSc!UpZ6qSE&bILMTt8a_aRO=vnc8 z;aTy7^sM-TcvkRJJ}Vx>&x(()hbC3uvJ-E$zO5cPz6scL9_hxrw{3xJI+N9HvmOeMq5zBI5SPU58V#Naz@s@vRsrM9QNUk)**LiVW}{}Wd(SlS(W9GI z4=t2h?)J?3ZUYsAS%KSYUI3fU0+rINBLghDeO-Vbu3PA`Es;gTO`YzQ?SZ~p%GXN$xJJ~MB#ENI_-Nq33 zhpPy7*4V_njtz6?k(R8{o}M8VqYYQ)RvQ+kb7dE0tveOHy>;(i8K*;e!n(EJtL}oD z!Hb!5l6d_M)0J&$X|B8b>ZcR8_V7;nL|?D#5IYhjTpF!HWQsGmC41Dszq`Kv6ZTw0 z%XXs@L!90`)Ewf3wYL3{N=SoR)Yo+wXi#Gy4eFbIph4xisip$h&6uv%TvLaEz)?N_ zI?(0sZl{bV|NO8sOLS3T*5M?VvRNyC00tqW&MQprlMdE%jF6!vB-aGPCevo;^b4Ox zWk4d-S^q7dL&Vijqz(}eNsgVOb$MrG?mV%Lw3`x13>G#@EY$&yo&I-Xd4Xdm@i8u6 zj_B?l60k!n;nyz@;i>rpd@bb!kLGpfLq;nM+^=Ld;KhJrrvT*G$?IaXFYHi_NfBH; z=(=vU9#b?*Djp=hOkug;_ji$Q)3ZE%;Jor>Bd{B7geXA(`fA-KY4>gk)l#gDeeMUh zHG@1%pxQy3L(4#SN#g_c>v>K4I`yUHPhj!6aQ$H(2O51LtmgnzoalB2mZ6|-Fqg7! z5Ks3y6*PuHi&4R*fPW{fXI>WGK}cE_mlI2LWR(S-Dk?r+^k9{BI&lzu7`4f~X#A0c zb&-NvH*o?D1dVsZp;{wAKOvk+2@WVtIbp0xY2OI}&}k~BFED^)GbfYpf=RRr!qJ;4 z>^A|ve~#=3!Nm|tZ^D>juW-Vxd#5b!1n?V`V-#5YKzIsvdN39o3h2*)Y)~Zn1j6s= zN-e@N){YL`MChZ#)#cR?L?-enj%0 zY76k;TucnyrPtqH2qsm)Xghv3Q7}I)WDIo+fC0hDik;w@#SE#g$ z0HZhZ)2O6kfIf9Us+&Fdu0?(sN}meh;d9n4eTaBtKNl~T$uaAS={d;UZOhF73Fdq}A3z5CzUJ1{J{hMXoYe z%|ShjC(6QGkWjieK&sTup?kNlCC~O?sYu}=HCO(mQ16!4Y$**Vq-MWoo{Z?w++#$@ z_A(D6{gZC0)o-xs?_k~q)N#})kUk|I#qxGG1@ z^qnTr4>}pA6huIv(|RrMbmR$N-Ly-p$5mTd7+fM;3|NYrp#a76T#WJ5+~-))D;~%C z?;PoF^_p-=G#S-D&ABI4rBheQ!6k-I>Q|dr+K`7x}aVX~(cyut93fvOzMLEB~Aj5(Ug=*l@ z59l5W5Lo&*pg6~%X@HijFQJG@7#)iJQbVq3FklNRL-L&@pz|EnjF*J?Hc>-|5@@qd z7&HD`P#g&$ese`xe!@GKBWjCa!AaPTHWE24NTZVRo4A`?%xVUbZ?G8gnUanae(z8dM!u!r=WP*hmTDO){DVPUa z;+A0P^3|VH>+WUMq=biYk!9hY1?Qfanrs&h7+MXommE>+AM~7%?Khbk@2f~P3-d5+ zYV*PE!9L22E9ky;`E73D=-^81?HA@fQUdM~vL3nW{WlT>)qb>z#8FN8A)UQe%J)j+ ztuc3@9Q2xsMA4ne!1yIGthc9vo$yIeCmOX%4iz>Y_P0rZ_|D17Z1c_1&rd5C5t4)F zZtFK&?k=Tsh*l&tRJV12Tqa@epirmCoT_o}yRbrgZPGRA^o}+nd zdSE}V1*;Nweb3?X*$wI$X-ULij+(8VqlSjHJ^BYP_~R5@dq7qX$J=h&*Qpk7hV`0y zp`%)z=)*e~af)+rW%C|yt*I%v+X7;N1l<;@KSp%WR=)DHo-$tUwjkYnk@?j31+5ka z?zVt;3st%v)avZyfLWIxAWTdV6zO;4Jf5DwA>ceV$sn*cjQE6KQ*CQor#j7Ur58ia z&Ii7G-VR9YyQRa2rL|yhC9)Att)1%`Zicd0dUGmHW8O2Dln(cg1bQhlYbhO>e{r2Z zjstRjLFKPNyMZs477k)k~&8qsqj?8wJ`eD2)P*YR*I%Hc74@ z^x8?l2N%K`)mlxUQ6(j>U;;--JdD0zCTHbibB@M8?IFjrHGsn&Tx_@SzXjgr>1W0` zyUQ`sr-{A6^J*uv#}JmqlmB$K3g*i8Nm6T~V4__ofa5pb+uHbUeD z2uk;2ZGP?tveSmmOVDjd>%wM;KAbn9tCDZN(BcwyYz3e=$=dls(cuNr-wDWmd{BUT zo;fK8u#?+?lO;@2cJQPJX1;v`x|F8RXKoHib+Y^eNMXq~1$~D8@SNyxRC_~bLiAxjbOuhDJOf8ijSSg+b!*s-n@L)oDx0h!nkF<|?4QvzyOA`_?ZB8+4NY1T@m7s~NAfs*>Klyimh=|z zMaLg*y~O{C>q_z$y)xK5d<}I`9s? zO*6hBZt#+ceiZNyeHC%_Y9sD8$vae#@iF#dDL!MBS&*O4d6W9mDsIdR2|0lb4?i}BGX7J9n}?-6u47v=_8ID3=FNbN zXvlKeDV7>VDd~5<3J4a>q9?^iQah#=)7*3f4(zt~89AKuQtssj8BLN; z&;b%-J}J+=GuYwrs1HW2GOK@Zd@eyP<@^q-BC-gHbII^bXA76re!^pt&C~Lu5UgFT zlA^a{P&X~yvhO&uWgiR{C(|fs7(kY4woEacGE7t>a3mneNUr|yQDLFR z6E63v8_z@&Uil4VWt!?{p0Ex%eB;y1-mvh)F}?|+I5{;DhK*VrLg}wU=)Jv9nGmZj zl^X_Q=ZpiQ7%kMhS|csP@PjNZ_#BgZg|_7UX(G^^_5aRx=IQ?(-&lTtMCUF})IUfa zN`P)S(^dEr+GIz%^&<1ex~;&Fbg|c6oV%YVE|PuHwnE8W(h6m|NdmE(8>w)H9h*?x z9O=7gE$}*Sz>`j1h(tPQ!FWs(E%1dAB-bsZIu<1B0A$WWHNAl0YD*T%#g#P5avWJ} z3jf&TZB+3lj2`D!PEt8ES}TZ|{HaBSAO*VQ3J*kJJV?UdefVnJ9TXaKh~y1$o76=aldO-NpDu!Ib|$7UGKX9eBE06$NBUl8ggVihCTTO5hbKS1 zIl5b*(Zn(Gr|a{86j9uUqB10;&#^j2m)wEs4>$me1mf$ zvp7qcu+WLNFCKKF9q8b*QP+Z^Y~YJp^%OVPwnALQgUlCovPknl#zyUKJ8R; zzNiHT_U|jP+Wb-n)%6K1vp4^EewGqA377gvoqgk>iANZknMGXX339{|VFD^6bHcVjR|iGpGNjKKocz6~be zG;&ex+aM%J_{qCZ3(fdJ+@L75^$Yz^p@atctCJDp;w-;WL0FUysQ|xI9b_KYhWd6O zJyJ&@oiJKti-oD#zr$|=FJ-V}lszrLV3P(_+a2imu}!F+79_0rs*avQ#d!`q=&6k| zpjSQ*xCb7m$^&kdY6`-F8VQPOM2NS%GU;0R-Vxbn;$!swte~fUvyO;Y!HiTh z+9DM~vG#sz(IQYUW>lz2v7ft9JC+!Kmb62;>=VSzD*_Xn2OTOke?=LpD z$BP`A1C0p(R+j#61R~O8bv{tdPvQ#*_BCH0vkwYjC&{cpE$4#F3a;h6p|$ELLxFOp z(yvXgNir*LQ2{6dSxbsQFr)~C<`W_UF{X$>nBWM6KiD#7sDgcjX{IL9+516$C;g4m z&I36IpjKLjS;PwWd9{pDC3G<-pkG}a(OoSzjL^u7Sg~QN*q)f*&6ixYpt?G?=}<{m z1J70OOSO}EIUT(p8flG_l?8$Fr!3)bvzm(;`#ZYC9`*>vEonL#+?zT&NW!aIIs8MM zGerUUo`qvrujyGiW_-gJ-9Cl@`zMQG$!k|bccuLeLYDYI_MHPYMOIrMd22alh1Mvj z`VuO#bd1}9?+z(0xop1fG*Wz3o_td_RnYoqbAFG5nAuVTrchV$aiC*e4U(Zy7vW_A z%>TX?7s6vM!k_*|9Vgz_>A#`HHQGstJH(vU9_7@etduOelj)R8pS@KZtXK7_Aw-R5 zTU)2i&65LPp~+^giPE>Yt7^VONn89Nf%@(nRWfj#wmxhBpWWx{hGSJM%^u!t^xQMr z>IsKxPetAv&X=1$EBRq7X2qY={IuzM7E@boMJgdaqp>Bn+Pu^3;iZL$EjU$=v&Q}v zeV=ey>8TPnmGLB3U28V2nV6X7x4g1ILwV%ty5BrU!k2S&Y)lC##^lZAfH8jroNn4 zhexrVzCgm=aokQNWiP`||7AJ=bUvy~8R4zN?q?D_QusNktX!*~IWl6@NXUzKF2zHw zJNi@@s+a`+UtNRmSAo_wO=NcL1PQ7>UV^HR)$PtoGzcqqB2o zosWgv{F3!yI{%2k^yEi%d)kNF1@}AOC=I{~z^}~TlIPcDZj`V|wJ>8cx}Bkt<+WEnf>QXQY^e^ylbwJSELtNmBVlT@d4n{U$yVIk*;N9yyNq301T$Dsz~ zRV<;p`7_7n)=ZH%4sQqbcZ8ra%5B&-4cX?+nKjvvy-h!;aY?YY4C2`b^tA|yBqW%0 zpOtDB1LQ1`eEU;UvmXapSSIq9PGTFhySbQN;)q7>^aJQbFLlHNyKZAyr(x|tHa5F; z+yQ*|+w-}h6Nyp!4T9-Vw>7HFvr%Pg$&VdL&fr%A`x4 z>NMZT(s@`synDGsGxXJ(e{|x{c_E6^2FOtIt{8M;j?f;DJRk3%+`t~btQ_(p$}P|l zcThdSYQ?jg$hQk$O-ameI+1srWA*_*8O_gN-gBDFobL2NFr?Wb^d^LFz_F5!tzyU0Z$HW#c5d67BlOH{!_bZvy1=UM9b=;3 zIH#8DP_d$67I|sMW?D9jAz$DeWOOvIEFnMGYz&z4Lywa4@D#U=8K6R2DNZdmy>>se zwk^+Ur?q=c#vjGxQO;hAbc=5kCya*$lz`5lPon{g*bqW}+y>pb)}R7(Q6jU3MA5I} zGFb^JX(bpz;%Nz@f@IIs6FO!jmfj*Bb|}9rh1NyHzW(eR=*|F6k zxQz1pdq7KDnmR{O0D6b40CcnUFl8X|(>k3SCy^lRL7SE$B4B!3@$SgvYLDYt{FB;V zHH}3{=XCyQ9KrUO74gzp#bvb_RDZ6ls?3I~KY^$GLiH!fQ@-!gZ0BB3{kg6QyHNef zR5T3;Xu3osUmJ}Z``(1i~;EDAA@IQjz0%v*kDab?tS@>|6 zl}WtkMg9j-RCNWIQjFLWw+^9>?vEazM*)@pWcTfQak`)}Szz;na@1Q9Y{&}g6p@a4 z2Y_(eO;Q9cJc52~E4uVyg>>sVVAhHjVt_pWpoo0sSlENP{iuqHm9H}$(^;d zr{6#Rq5iW-=>$Umxo27bS+S`9ys>I|ja)Adk`lmvVz15y(p*`72eSsUyFfW4K$nr= z%3-v$%97Mk&>%%s3%H1@l_g49@tjINtvj(wbe#m%}luF8QuW`pdK2 z>UBmuygPZ~8hbw5%#3?`%})0EXR(qUz#8ZjfT~ULILKHs^2x1@Tj5^Y5K941MZ5jf zCTNZ*^3me7)(V`4`(IJb1)xb|dD^M$j*}!KxK~u0fx6$?2fM6WjlRc=N`%EkWkDtB zH=d~xnukK3jz_e2Iv7zGXDIh(TGd0Gt^s{6CZVb|d&k)C=qSnRf;rd4{Md;@LIn}`%{m}e z>)mLeY9$)v1L97&S4GK0ze{F5yu@+F_o#0Negg}OUVT#s0a2{3_n2MDBifne62H;( zx2PujJlRJJZ%hW+eGxD6Nf>ZSDwI9wD@IoF3$2%7_3%1+e4`Yw;TfqTm278>(7-l4 z{>Om6)%3v>ZOd!W+0ff&^ZW0R56=UAC8J`Sh#II&aqR@x>3%U=!?QmF2V0=5P)tos zFimig)sg4&by^|X+MN$ftMOUuOc-@nfnFI@5<;(9HL8Hbm9q>gRE%W6Gx(VvV(7ub0O?K zAddsEZ-!Q^EhI;MbK*g!q>1Mqp3KK*HYr0~UPo{5*Z9hT_NPItU&p?Qu2pg8IFmg# zS>=V#uNI70V~I6&|C-q(89TH3_){~y*=ynP+|#~m)&_q3HqSfXUS9yJ6rZ14u2LL^ zs}$|XsuYc~1=TOEAW?Y=1*60nzAn+>({lybF^?_IS>`=iN+pJKL#8g?Vre-H?a{#_ zKMNl{7z0YZbg@0Z79v1an`wfL8wke6TET(Q1EZdCvTzS{l>@Ls^-K%PLuA(ihz!|1 zR=pQD_lCG?>5&M9i6D@(y?Mb3he5yWo}@l$GJHY?spibam}0H{W`@4Z8~kT+6}vUS z9e~fXK|QA-G{RI&1#B_T`H%&{*%%o9pafWlu3c! z5j7V|$U6CGk`m~vini>HpQM2QqSh_n$?jgTT$RUuhz4M5eEIPJJsw{JMTxj|%M0zF zh&XeL__+0-wzT9i(3&6``QG(-poaIY@D7rpWR!7nte6r(P2tp6O5Fg#)zIQjVo zzc%RA6{3ABCMQPSyCy@%-?C#<8GCnr&gd&yQKlCa?1}-PR~HlsVWjEyka2jxQ&3O9 z+k1mIY{)t{EdvZ$$4k{WFJr3Pws|zXE2P!WF*Aa$GK)wH8g-!yn38He%RCOP?{Ck+ zt~zJPTy-=kTy?xit~%HSSDhe^Pk-gALudr9I%k$$b?yLH9d?u8;=2(bfGKun;LJZ@ zDL}UoF2C8mv^H)L>(R}prC5Xk(%Ibj3$?~r2iaTZuRv%MU<5T}Mls>l&oEzoPe(qt z0m%)pR@!IRWwRX;r3XU8Be-J+$mirL`Bk9-nNNj3ty!*<2e=8UT~x^rqkvGgu6Zcj z0itn>{0}R4x5Yj8JC8$_?b8R1oyT1cL=~t*;Uy>>+=jTfz@6KAj@b;QynxY%3oz0{ z+*~j)GepZ=;LY};u#(d=H}GRl)HXXbiL$kW1LrwDu_@^5;8am@9jcm%<_5L z0!8IBs|TsTHCihwcn`S0AWty70SMWwAP2eBVNLnb8h*DT^RNVsp~&6-CYqh-isk~c zie|RiU$Tp8^uokFvrs+r<&>a*EJjzw+69tV=KW1%=0I70VaUqz^7`uUNFC5^drk-m zGYFxiO{9|$zXAXo439gU%!%iUT+}XJPp>{a?EX}-?~<21A^6V(%PeQzWOhB0q1Qr6 zXS-27tYGYxh8?{QAMquZwo`#&yJBG&#;r#V!$4)lA49L{LrlFdj=K)xQ+I#N%k34#*#Va*OU-0u3-5Xc>A1 zM_6YLtXyNQ6Q3;-J1er0Swq5F=peJ`er5~&RCn)KEPue)VZgj!k4Ur0ACX(PB#k`t z`8ry1{*`%+!<^)>{<`VPX4wCwdOGoS(8H9hgJ-$=6Dk+==Ju(MC!c&V3DDB=?b;k= zek1>6mRrJHZLL9x_m5h}#^cSkE0mPg__eHDZGL^efz7`LNOs00lKqh>%Hec~!EmZA zHIgQQR5=JA(yPGfUS^}L&CH`h2Hzk?twjuk+mp|UBliIRSiW3KgP`GPE$e0C`* z(R%q0p4?BfZRID1iDN(APi)@uY02pH7ce@d0Y;~`!07Z~x<}RrTo~t%`ol-3*f$bw z2ux*irGfny*acxbOnkN1{FAck0-yQade+$4)l#Z)(KmRScBysK(|rw``z&0R#f@!& zG?KK;Az}h9)>pDelz8VR!wFII&4VL&Ewd?!re-#qFPy~o-<&2JfkW%pg$V2%acp#+ z6~tpbS!EcIQYNnHBcpbpGARI+>>=r-m>by(@_pp*j}W3tSFIt4Z%42wDf773C^I6@cVg0)D2T! z%;odspzmZ(V7O{=ha~&eo=&lD2b3@kwL$wH~7BJR#i1qp+V}mGugNZlh zS5yyrEmerQnv#F95oV6F-m?@0EuaS$m)l)bSg<{D^AxeaSj!6(1UsMOmTI#{%=y@_2tUb6T+?URy-N((=NrZOMTVkXS0YRL(B*Pk@X9KB$JwAybaa zL=}m-lAHR-!yGb6CrUjWbFq>=x?^5z#J5x$ZOr0HyD{Vay-&}0?hu6P^ELq81e z6YJ(cCe;Ckq9X_#p}L^!**P(%G~K%uj?crLgZy&n@LZg+m^Ws|I=x zTMD;!iwxArs%&eo(0*IjH{1ujBZsbVwtmUsD-ggBTi*64`~Lofqi1*XYCPl>>0$JD zA{&ULB0(pZwOT1Z&5D1sV!aq*^wMxHW||ovDha6%*l$H)ehe^%*XUlYt_+sK%bIM+ zkxocSDylkAIX*Ws{AK$0L|hXrhA9{ogu|EBCw;!j)ff@=wdb$j;BS3qoc%6BA=A`k zYD&;!c3|eJ>Hhl4*5Jvo8Fww&_^v=X_tYzQ6CiWCyLk?bxGkA}_RrwLjaN(09LK=1 zlepEW<)l0`!f-!J+(u^d>FqJqLo1!{umLF)2J!V4;37&vryKxK32ovGzWGIlUI1OW z48RLOVHCBshWlN#kr6%~xaV#+(jiA{Yl4J>zyTaXu}{qM;4I(!df^cgQYAnrt2{J> z7kG!EkQj_#%AZG3932Pn)kIlL!w{-!KXT{b$lHQ#yW3*L3XFK*&0cn)0)Uv$qe6WW zv1EZNwI(5`HK^l*_rN9}$u@ECIu9ru>r1azQlc%E`zQl82r-KOM)`t~(8Dpbr55~E zc`7s*gE`8X4Bmjl3FJ9|DX0G_uyMK&2Y8jEcX$zNA6PHJXdQ(<;2#k)=5|vM=9?L) z`3EjmY_m8D%%`xE+xf4Zm*;N}SzA^sZB zptPn+Tst*lrgrPydL^5{@U_M469$?mlNCP@E;MlQn4P_CF``u}VC5M4pEOU%N5n>E1W*+R!gjqFqG+g9rv~ovJynTm9;+e)@)U6GYn@=o}32k>;ve!AXceh{;h=U9(vquAWkSs7wF;aAK$iTzwOPf4153HiC9x3*{G z%b3Fccl9E~;fm+S`Hcm?Dn>P7B*kD+8}AU4pr3*?fRPgNJhqpq|XX>~g&CchQT+aTZ0+3OetT^Q!dXg3c5S3cLtbJ#bYU#pc6q0cxtLn<( zX20onTMc!wlZjrV56kg3bf!uwYjCOY#X>V(FTI4W8I_0?l@rIM%B()jT82fJXgeGG zdPfULb6oDMFOpYMAQ1GMBK4JZeY#$2jUH&|h$nU*Z;cvz&tp@IztY((mfq>mS8>Hp z#L^09m^ss3PBi@s6e%r)&*aiy~SG9D{)+_j*S2azT_gP-vObnbA zo4D6ao5A#=)GM(iMhBZXZnI)+qCG#0)=yo`O5$adX|!gJW%QxiD>ODEmH5;1u3@() zhg_~ttJisp38>F~v>)e>f#6!meC>!Op~2tg4;Q<_?r*q0P6<_;TIVHay-3PM5-l82lROw8e+$ z*#kN)flXXJj@+&-wB4(y4Xn3?Ht>pc7fCX?@GvjlR`AY+s8(!1S+;?VB=9)CB|C9v zLI-MD6**$sLl_R3V22BT$ZgZMxHgtpl9Gz zC>QRb@@rm{R}O6VfSnxX?mPF-9%GGBF2VlSLv#}#>bUhin8_4SsR>CD{B0hsFw(!7 zAFDQ~Wuc((BRX#Yo8j@@p(3nHxpSlWm1{;7>BXIQ(yEwr&BEpT44FQeq{!2I>^9qx zyyj^_FdkE9b%04QLZ@R)X2PdVQeRb>g#+K9F8Ett+yA(is%l;JQ{>x${@&v+%h=1J zH*Z~DN}&1Yw2O4s#56XoCqHWVtfliKdZ90z_FM@B=vX8EUDDlSEg*oF^QPNYfLSfK zV|f7l>$MeCW;E^|Yrb#T$|qkeer)y9hXapyeeZVT+$og0Z)uq)O;#`}qJ#8z2Ui}8 zv)4w5Qot_cxpCT~JC=dLN%NNy<+&dmB^g~fm}Q0EJ~}aSuN^C4CAkOdeT@9afWKzw z)M@;ke3Y#v{Bs2-Z=fsgztg&N+8KoK_nLyMd~s;#wl-%?kIE5$6`XlfrlGUfxOViW z)Bs%tVT)YZ0PmT4H3iSOz6Ta+Lw82rJq*VxV(kL9ditH}w@&z1A(3L=#P`H=uc6Pf&8ON#S*l0v~oQcRwkk z#Si$q?!uyO>E8R7o)x4E46gX*Dicd~Y)lz?23MJ#b4SFRz`7{(_c^1%+}rD&4sv}8 zdSiQQ@x%J7^0noTxTfa_DzAD4x1g(^Fp`y9D_@Sq=zUIp0c*&r^J|>eZ{5blEq^U2RQ&Q29d7w@Wt@~(oKF#bT1Gk) zqYRwOd{ij-!B5R` ze|Q9c4X6$Wi<1hgHOM2C-IS4vZ+%lwq5kZ|sa0K*cN6hUGjiK7-VdxXkqGnl zgMv@ey%D!EeD!JYFISK&z94__-(ZjiF$m@fyWkUHwpGgv3;-s zEEDrGz2zTWT@iL3tk*MLe<}xd^#=8&D1J|nY{Fqv0tXZncBU~WcaO_$XORwh%jrq~ z_8;HlzYzC$`O-Zuvv`j$w3}M6a|4a1fT!DiCN*9`$8>(0h1-F27U0tYPNx(uLzEB6 z*ukUqC&@t_R3z*q$I9Z0JY=wJ`=1kKr$t{=K}XArn-Hh>+6r)b39fr6t~5K)07l*1 z!K(G#Z@2ZIr5zW9^;3 z-r#7Gswfk(J%u@W$k$HO>TQHwbhpa3GUf*!-JRA+N(!3&=1l>$Lduq0{yG8IS^_!G zAK)x0x+#|=V-;r_vObY$s-fadpLjIofx`nKH~uNaLwjuLp?Ap5 zt=E+i7!Avaog?m-BUE|LUbEhzrxw7G;(S(ve8s$ZA?0B?9Sbi;4PG(b+v0tcdm4u) zysjR`c@aJ_X{ZqtNy^ozN;9& z5&#EP|XhH?t3-(qXC!V>*LUU<#R#HLkn@2mCHY^mqh`rP!+U6-irJQ0K8{;|7r=zdM2 zK(kbOiA?RD@ykSp1_RHwto7Hdt#|Y5-l%D~KCefV?f()vpHgggC?m9}H8K4fc9Ox6 z(3bjnHspI-ADc~MClsuQeh7MB2`;AU0yMd7hhHUFLytMn4GvPc1E=(~%J6K)=;i7Q zpLQi_y-{6Tv+m6I$6c3gWIuZrbLDg88eXV1x*J#I?;2Cg8y*{j(X6Yqz2+V@>*ekc zz#TEVqV0v#@cc&|%g>{BEicY%6{!p)xXcz|nNT^bXZx$lRfP;I(EgyfOIXo(jy?4E zX?(=D=K@?%gcb54k6qv-_z2J(sCF)8%i1-OS{0=BCRSsUlK@v&5R7O*MBO{2VCS@n zJ!{ve)!;at#m*E<9Fvk`auEm>OYlDn08fiLMjixGN_Nb~P-qKf6P9q0ntZt%PDw*a zn4_Sl{j%LHD83u~K2s^_6b7*WbYC?Dsc3f^FC+t&0z4gg)=+Cp4xk`Mhjs4@sjHAsD&oQ(U-*!M8X zOYVq~h(RmAWYP2qC0f<8MD75Qc8;>5IlY+h!n*MW`7dQbY*Ch#L*8?bFI)jRa0r#Ny_Hf;g3>Zj{4pT?h6*y{F3{zQGb4{gW(8aw977wbuqWK z2uQ1rih8669;H1`o*savNH>JqTXwT@QCvf#c5?g)wd`nTE0D5-ljw_~-ulN*7PsMJj4H@h}x4{!{Z5sH(m)#<5Xt?ihwGX5NiF*f-*elw!Ip3MNC-c&Xb z9{y6*rE%1p^94ij)slq5-D4j^aUZchMFpl|yfuT@-qp17Tm$3n? zUu4S_l*|MPA4&JgX;iiaLg(xP>s8m#d~6I&5VQRs^o0>V-XZ$HOS#!EM(4O>17kHmgI^K8jX0jR^C+$IQ3CrP@j)HeQw-A z3bDomp!+N0=H9z^gAH?9)lW58A63kJ&@JhH8#iVYqZAln5~ZlZJo(wD#6P;}hoK># zd&J4*JIsRm9fsUpD8k-~Ei}!ZawH+qhr=Xj+C8^*@40|uE1xd$dq5hAo7?JtR`k{( z4TK_pCI)}bZPQ%HU?*2PrLe5#U|}&RMAtFH%(u1z8s0U zhq&RwOiwH>^TCVDJo%jh&F4M%mghUUkQj;i2yoE-&5r+EL=7dqjrTlCzLf>+e47fs z5FVJ^!D^#XIGfSXqNC4=|9-V*XXjY&)i>6L95~G@R^CM$QUikny+b6XIxfxKj7sh> zHK^HLTfd#V>{aD?PRn%R2f@v$e2v^n4&)HRkP<>{EN_J%#Pzw0(KV5ZpnY3dd(ZJw z<9D9X-uTyTTRaSs=PF&qKI6)K8Hi3~a|6b(ExSQ}5S2E95%18r50Z9;N6VrSAQ33p z!E)QB)RWgPVmoNHs7VcSn{7!(f$`2A%7KzPhdg{j32{ zQL9*d5fp<9PMQH&Xv>qd#pL-8s9v!G%m(5~UphqgkMw0qsuju#{B{=1=#$`-5|YYl z{ujgJ8y8RC;GVZ{Rx)~*5PnK7>s+9tRaK4WxCSflT(Dh>SIxoOOL>H)4>^BecliV5 z;>xAG;NnsY<&QwBAe+imCsf}*=Zp?nA8rN1M|(eBak#ae>I;>)M{{_&+; zAxeSSQ;K};2R{6N?7ay%ReSq4-lRc;3Q4Af3>k`$GNh8IkTIDmp=8KBg(3+dQ_38P zj77+N4#^bCnE7BMQ#;#~`Tef74STJ<&*?nx^PKXbo$GQrU%R!}wAa2r_h-0O zb2T5v&mI1nCwkGG!M&)@FrOjIBE92%b*4i0WAlM%N^$Loyjqj?=f-TsdIIUSSzTB@ zI%A2whdQ&zSjvx>+h;c=)->d(9^&zJ2w9g4xX+*2Z~Qcq)sw+QAf=Kzy|7JmTv~j+ zoW*Ph+f8QUn4E8xM+!5|QLj>;o4Gb~9rv0u{EB6cr`h-~faAlv;)XFlXRj=F%C+_~ z(^Eb*@iaHk`uS6cMsi{F3Cmc-BJce5;Z(hjub(BtE-NK?TIU{07~|R2zaF#ODgP?A zrtpG%uvpL`L2EJLj!5$g4L#EgoxIOQ-q@DOfuB%@XPnt3;%sVN*Eot}^B_-gfj{#43GDtV?)ljc9C zhkTZb=!9L$mV2jzIw^bs!DE44jGq3p?7Eo&u!x*XQ4%=y`_5dHF^aa15#QGDZQ~3xz4tg6iuSVDe)7@KFBxI#!{+RmLt|cC!$V56lkfHi-8fVji+K@OF(`WSXY_$NiD~EI zFVz(Ge0#!qZs+SX;0%Wr*L)i(@pGm)R_HY2vR7k7v-07c#SB2$T`+_Nw zG_~8FvG!{N9v&(%JF5N+3>Rz!I0490Nbsi}ObVo!QiBV~`L1}T)ZG#}O!kbzJOHN) zfl+(_|TORr)PF7~~hT|x}Qd2>X+l>8Q~g<(&9r(vV7A#=-=kYOUB zg%NyzLMz)lwZa=AhKUR!S?sJfFE%XQI0uLsKd7(qcQ7&T-oB6Q{*-9?c7owP=7uBz zN4rGU+MWFW8B^;Kb$0YVraY=uMlVEE=7h(mNM~e;{^b`XdJUJ_QBE$ATiSi*X83yQI4RC^OE~%YnK3wjNpURJ9t>&kR#o~LfV%}*S9$D6B7RPEOEgO z`7@fyw=-&S@8hbBzFYPRIXTeXYAzt?JN?h1VnFF~Vw#3o9-~k-!>Nd6!#q&tLv{lI zs<)YcMCUd|Q~7e^NNt9Cq+QdmlQpDE0`9se;jL-cZZ*e zcxA+f$VTd23!q5E4aO-m#OOd#Fy6!BVU# z!FKXds3_l5dVT_zF6fBmb(D9X9#9^8iCYl;tIznUqGrWu_Td8mt>G#eW;1Lv7lvap zQ<5ks?FRT5#xvi^(N=2Nwz-uef6#m{IuF=Jhtp^z8odraj*cM#B>jp%IxPewgDH7d z+*(pt^0Yb8^$RF-#~`5|84NAU(Ps?ewkhn5dW#TzJVeZYht9Eh*|`IV?irph-uV*Y zb;a|=`_B4wB-(_!z7NnqflP}Aq~NUxCP>r7>Gu0zr=pg zKAd&rC&QzEnUkODm$_6fGsYhrFruiF)c*QZa-r6<#@9_yi)ZQ28-56fZzt1L!*o!RcmLVrZ4)GgU=*si z_ekI|ou8ObbLW{NJ0%9awcNWTv-c^9Iv#GV?CMWFv5H-Q+7@Vy)QSrrAfT1^Sq*ga z6TW=+xLlAt{HG+XnmHh8X-8m^mRx?3>kr%9h2p_8$Gg({v~m;mj|XSHN&VKk=vlD+ z)S~4yBOgZ2AD6oheW74mtCVwafAi z;%s>MR66F1HJsk_@+{sm`#DqAX$_NfgBk>wVD=>Ph0F346GuAjj(gFtbxG(6W3@N%EsQTm4 zoxZ4NuGb+R*HFQ7bfH5l@7qaS;j~@F#m_uyLcA0969X> z*6GSO(@=nh1Oypj{8+Iyf$6^isp2)gbR@O6+evDA6-mNZa79**4eGq?s^2djptIF7KR4_EJgjerWPy-ICN`o*a5I|??5*bUc0?zxec>)pVcbZH6y{1P;(v#TW0n6}?PY^hdy$Z6 zuc~&Jv5oAp|>aVsO`R>WTEyyLwLz2Xfo5V8BuMxqUDOf6egB7Xghj)!656Of=iM?wZ zy#6J25>G>>HeVoCY3E6x9h~rOA!$=D;}9d~Z+&;B?>~(FYXid&PRi&NCuQ)mlX6AQ zzVb`ePCKAJ*ZHv_DuSjF?jE1XwpubM;BH%T$hP)&^I^;E>`wjhB>>Smriv$QczK*R z_-hr&hBBye%npVs5Rl|p50ZUj$UCvZk#d2QGywVLAN-kAAhGKaJtSaU?Kbnpf8)R< zcAX5dRsTpuby0L+G=nivEMxkLX+vX`kfF-=EO~~KDaEWCF>1_v@e{CO4j&coG@LK_ zs#BSFOMb>Zz&h^PSICRW_}d94Fgb8Ys(+$i=T%%~L`4uZx%cOuo3;~^s!uMG5m>A(?Vs|s*KN9H zt3W_V%B|XlLJn$M?wM|Q!>1*>p=7V}-cO)PfsvpSZ;b%=SM1G_G4?YzYEqm#w0RwR zLH^k74Evl^jAcdL(MXBW6y8KG(fP!CJtH#|iIlW#fr8i;Ey23%JU2(F&IPq`+8K0)eKB{JO_??jX(<$^ zz0$_v?Cg_LH6Z@XSUaaL-WTWm**bCCqDmBQto6NmYg*&S8G|v?>wkxk6m*dVUEI_n zC%g^NP(k}7C?3O|Wsa$&W{f=!(4kf=+&)n)twN{QKDjNuvNf6P#r2b8@r4IlDv~z1 z^$Ew^7D@lwD_5r0N2Bt!DUN^mmLylXs?+)M)AB(LcK3crN&R$I6clfnmc*7sr|Tt8 zC0@}so@ZKP8j-^B~U@ zr05;!2C7`V{mqgQT-T=9jZ*aWySji{cT)*H6{N8J);*t}Yy0Is!2g!_pbtW~cAoz3 zCCY4}&&5*?sC>s);06I_=fhe^o(tXpXyLSgl=n4I0E1trx&f5jhqrJdig?J^ixY%& zuac1{L;~wmL0%P-zT3>@1w^?(%wwUjvcD_8fFiTC(@{zhLS7`=Ai2 z)dTW`qgPeT%O+`9t{Gu1gEWi6Tdv7rHAKib@$OF+l-mzhHU9&aPWasnI7z`K^^c^) zz)!awzx5PiFCXQKBW*x8e_;bM0E5T>y5-1#XgT_?wj3vyTaIcp)>hY$KepuNjQ0R% z>}`m8M_p%FB`d#jV-mnW>~;iYyfYBiRm;&6Ddt#3ZlTpnK*jk0ZT)nV-Y=q#baTQ? zAtU6{l=&ac6yl;8MXn*kKGrIXnqjtFLz;epX50*nCDc`bOq>W; zr?x`pF6j=vZL44xya9wZfdcm-YMdYB{FRQ-OlN~zUd#Ui+Kc^m{NJo=xrhD{?d(=^ zgI@`@5wcl`DYSdW$^_WiDSndIm`MgO2xx`F1cM)v;)BaYzpxXd&sMFROPG) zCqXH4kqqdXM9cYwEbOjj1;hHQ@G=_tC3_N0h<;p%hhrNknF`~o@3to$ttq_0DONixY3S8aij3+@IJzmjK}|e6lF-B54zL`nEcU%8-z6}P?R9a zm*NS&Z*PN0U+mq}`&m4QF7|(cp%Y|IFY$yyBJqGHEFVLqFkJpc3WH3q%fbJ&p;L65 z-xSy@QamA^50-z1ym~O_TDZ@r>dQ%zOoc-?|%Y32Xu)Rs1L~meLMTcRb z?fvHEaGtG-alJyH$3ZqvpD>s(KXayeO0NJ%(~x5($0NL;9=cxM#iX%!m$=wq&e|D7 zGS8h^H%)KO2=Qkly+6j97$ouib!8R;ChY}RqrJkUa_sKYKoQ6$b*bjf)xsF+n#i4g zVz~=;4%x#&>__jWHVh6_x7BgV$0|E_YiX$lmFiBZ{5EPm@7~~1Z>Cq}tY+PCp&z$r zlGfxI<>nJ~1 zWLN2l31=GD=02{`XkVDn+t9eU_H(Nj%Oc|)r}=TRBbhDPPq){xrD&etHCG~E*)w-q zU%#zT;`%`Au0PG@(G}`{8v-H3Qh*SFyb%G+0J8^*zhw+KQS@Lt9#p~RGl&UxPTZ%w zZ$-7r;QRnkh5li@z`g0Lf5IK)*W^L?lCnH?qZmvwA%GCj!?Kj87Nr2eYF$ap#uCUJ z)#f!7=S!so>`)U;iI5(Y0@w#342S@QFtfACkrZz=Tl+hKXB0wPew(Bil|w!P%_0c* zfvlp4P2JrNAv6F95!1Bc2pk~1K+l+kaHx~-QDpOHm-3!S8D0S;VlCSRf3KySpBOk# zh5&Ms!INZK4j^ z1>dm4=mZ83kn`a1MZ%L9zaL7?(e^#UfsfW9KxKUK*hef_{*7*gR|s57Ch3T6&B}Y1 z9-B+FGI%@DZ2j}1gxiJ^c~0VPd>(m;D`XvEt(~1krZW7O@pLfUWCaEzR|0SgdBtaZ z&LQ(n)<9qPf6CMC1%LX#n5Sd8>SX#aLNZV$U;1bKjQ@ag^Y244+`Swh0Mz~qFd1~e zp6;MS1?1oXl{G0toxD=!ZiJ^6E@kB%Q1n)Y!1Has8cao$WbCm1S7q!dx7f7Fp10yR2mBrO$i&e6fdMY{Jc~-00(-MR&wc@^&?Com`l!9Jg#%%2w2Evgn!T zjLTDjn7gf?oH&9D3tOMhUU>qDyZf*DA~q~|B!5!A=!4}!K2~k ziJI0*y;RW`T@J~r@-}@Da&}y?GnClDv;;S3W(+&X!bYHv;Ac zO3WAf^j9{0pL4aPPZ#lR(3IH1b=+sp@Gy{GLW-y*P7Y-xjHfwhw4~02C^iTv%{Vkb z(xudg0{}n7_xSF#P=Ga;I|gfv`agr9kf|n0Wy=H84N;|VdB03ZK{-1S0PL|&t9+&Q zl`+q;t;aKh4xe%B#E-GV)yhyyGT5op=W<^3NKYw}B>Loxzn%P z2AXj<>W6uWrsGQfr>%T;APBgp%t7p96pEocI+_<%z~YlvxtECiqqpO~p>z$6{6uk> z5FVua7IZ|`mj_5@1;{dRk;);5ysO+cI+5V7e-t2Qr43MxTSVW`Yi z>NSFocd)YiB0BGozmHMG3`zb0foD%yvl2o_1-)>eU9IkEI8GA%18@t6&C|+WBeg=x zQ6c2YmV4~{^^E#(MJ9aMhDp`iC;a##mLd{(k5vX$?K=Kkqm|Mj#r2s~XVZGj9tYChD8qCm+}pcm_|TiYs#uV=z+1eOwxCUUUW*44 zIJ*19i1k>Oj`OXuLSbw%H9{h#9CaYdKc>uqn>f4mclmPS>{hTSf(hnkLm2(2<^t(Y zi(g$pj1!WXvwR+Q%Bkcyk{ARVV8$>Ya(3pxzYmkF{z-Y4U}TQcA4=xy?1T}-E%Zz% z--4lCi+oV*f)>;GwqRJFF!6t(qo`mMsGu`#_$Uuzp{zsWj*ZKXn2fi4?X^7N+#=d> zH?8#QWNsUG!Jw>taoki~><+&{{vhGziUpgXg;~|s67lbp!df&Yw@*uCH@`3Uo}U@v zb$>SAZ_zEWch!M#8PpNzNU5J-0SxKai-t-s8M@SVVjBOiKONhEEUX zCVvi(c<-RADf*)`x1`BN!$R%#Dfza8XLBRPrz7VMm)< zm<-Mh#uLuU8d*(hj#a zi2ig$MmeF%4o@DF-;=Fo#%l8;i8$&tL1AY)Zlhd)_|>7efrv~VkauLh+b$KA-?OyZ zsmDq4)chLs<28+q2zRcARn`w~*e4o=YUWKHN;)wS&Bb}1lAQv6tI zf%>BU71fVJ8d@_}$9`m*>(K(QQc7*Qx?{T4uoZJ_QI?^GoE2~C)z0#)#rA!o6Nbl} zr+16GZ_RGFwln9+mWr*ClalnzAi>M%N66{~8N!GP85Xlal>I#&>Q zdqHb*M@?$;0=y@yM%a&-EN~%H!1vbXuH`a5k}6KFnbAY*`>G-La~G$CIaI;IjMK%%U0% z@ap+2gdcJ1NJV<*E^U=VBd3|n>hr!GrQ@;`Vp7oyoCsAi_)#BB{h%^fA>;|jqwHkS z42iX5tBO3UW`5&sRsJ}=R)AB^WVq;_VAQhi~}{ zY74$%M@^Z=z#0nl82|d^`)zrhKZ=`36TFq}y&7R5%B+DGQA; zW{VSyUO%?Z&awCBMh3p0uNwN1pU}A-%isglZUdXl>OWN(j?k3qILGbLE({NYLW&S# zV$clcTE`_q9N4=7+&@Hty_@4PtT?nj7}Ni;Kq?_dnomZ zeyoK)K!sb;Ep)K!v6qQd2(ThM?2OZqJXU0!E)ctkc+Oov_TEU3e@nwahD)ya@e`Ta zYKC16qD?V0&#OELt+Tl#DyiEePx0ZKEy5S)@rZBY$^r>C9Gxa$ zw%>yEdm4>oIY%y5DRzFy(rIid5LPX)h?Dkr#N5fMtE}lwP&^Nkjgo$EAFNG1ts+;@ zHKm`uZ7C{!COxgb;glRL-`hG9VdvS2;D>V#W8#{q^iRIVDF3=LzK0{*0F*!)<&+z- z2LX4tjThBiCwGwrL9BbNTkDDWvoi|i_c1iZ9SDYrT+$=TpR$~9qZW!+bBXe2Dd#In zux;}y&9|Lszwf}OK$AAASp{d=ex0kVcyTZaXKifAyD>8-gNaI#>dL z-;r>?rM7c5LhtL4grps*$)K0#1AQtw-IE61(Cq+ySZuq@qEJJt5gDlDS8(Nl0#-{A ziAC|N6Xm2+n zh~HnUjY-^}DvF4Ha6|iDlR_Yo04E>6p~7M$6^UQ9d9>QPgZNAMT6!Q!Kk!)fWo6%v z(rG0`Mi9;5*ibJ|dIkrmIwGVy$}fK*BgFCGX(#5JR~L&U@t`A=mV1T_Z3kr)y`4LX z9ps1~KZY{_lQz)oVBY@t$VV)u0z?~Tl6ceKZ&c3 zYOi=1&@_;7oZorjOY_@_9L24vec6nH*ui|gSynX%t*Uoi5$!$4YuZh6l=N;58`g)Z zXf*%)BQF6;cHxy3x!Gqf@|AbIIa5O=zQLF7U{GjccDZ+_ZwP~(n@;?lqDe4A>y|og zDwv`56)s+wDlMFE#bs67>v0n+Hp5t%Ub6e!2oNha!C7OJ=@>yNHmNsEP@)x^&=(nL z#pWPqJcdZInE=X8BE{zRcnpzZ6O_cIe(A4}btQP=QJh>b8OaeG8x)E$B;nw7GQ($K zQXS>|dw^s!BiJD$`%8;YFNix8t{Cc#dry8bU$N?|xQWH6+T}X^KA)|%^o^O%UpMH( z<%>q>sow0-oSP-SG^O_P>1MZu^in33((8psM?lqz^$s#^8}PfqB+@oAj*i!P<2UK7&*F5@y2$=*=86W1F77V&I5PuRBZ~aef_)ttBzDmnL zt%89lpoW~X=SC*GETJBf2x-VhLwz<46kEsV^?PE{b%(3~lBlu}Gwf(MQ8_7-GMN){ zOGPxd)G8vk-7>DC_G?4DNMdH%=YUrBa-msx)~wwYrJ7S|^fc%$OCwG`A2G z&K{k;q;&3>7U5?+dgU{&wEP(-iaRo+(azh71+`}02@*3n00@`Cw4-Nmz^l#F_fT35 zP{tC?;8+VlA<+zuzg^OEtgVlNV8OSvKw{0N9RwnYG@JOk89jsp#tY~n957xWHH1SO zhNtKu9C&!T=vjgs!U5xj+0%_hi2en9y98@#JfDM}=CxC^--f^1YrS?;8`Ja+v6-k& zbM#NlPtgZ6IKG>O_nQc}zfL=9EofMskZg4Kj&=ikP*cCzr3y)b;L6{vU({r_C!9)l zYCHV8O|$Bv$(&RDaM{+mQ*M-*AlXH(vceW5yL<%6F4%d|v z011pIMYV_yVz2F%fo=ki`+Hl(|uq*Ag`e5kK$;vCO zQ&0f=__;J+`tR2E)7hFThOc|ge3h<3ZLh;L2bD|-O7VS0999`mls=vxe%D&n=`Qe}abDL7y`r@D9+g&b0&`HZT1CxL6m#kFg{(!|t0RScg(HV|J+;YJ zzuSPDFpBJme0uze0#{5x^02eoK%r@d)^LxwS)El^W@D+ZsrfDpsC}PJ&DjjNzIA?| zmwC+=FWA)A2#nL%D|Z42HqAbEbV^+C2^RAMA)|rdq4s0RMw)tEz04Lr0Bs6Dl`A+n^!Nt>-^m_ zPX19@MEioBMS%#1{7u``1{@G<_AtxG*5CQVxVM7;kGJz&-L~m7`a_oo->321Rm<#E z?#Jz(WN@7A{E~I{n+|Vhv0K~VAB}uL3eJv6K(Oh$a51*`nAXuEy5GMmCO*HX`yIHJPGPTNriGdfa^>`SK-E&lG#Ot$5GJmjYaM4Tp~~Au79N?$l`=i z@h)Za1Jfl@mB=DHaC1T^y^PZ?Rnifo;@@8Vi9GYvb}q4iyPr|93{b%gl$KFMbuEBA zH7Edr2P+g{)D5975s%2(x`bGR1hlhwL(_QE>ZRX?X;g?HYpP5 zM`6U1FLZ0;3b27F8hBMb^bA_=2XIga8!}@QkB+n>MG23C8Nb?r8n}U99bUPr_&OiI ziq>M{0Z=0O))z= zB(&}4e0;N?+D|ufcB4WN0{1j%bcSvA@kmT&hsx|*(Wzi-`=KPYk7)^86La1me|%8U zN&}~Cm>jLijhDn<=@TePD7i(n7>{cON&8w5xN(YNEG=0(V?Kk#-vWhYRB7o{X)OZ{v>LJNTy6p#PN zBlpDgD2yiagH#Ke#gk~86QRg~n-)V?lQjTjH1ZK=X@4jjF zXSZJb&-dS!$1SeTU9|TX74yprMK`Ue1ffGahciKWdckVsBUVJcy-s0Wyrem43b2F| z{*!Pw0w^@xlO?7AH!7PGQGkL`{yk;tC<+j~aGzaVr3-OrAuuF?8s-}2hMy9e#%Q31 z3In;PZ=Y3eP0VjgtnzNO<_2M&`Iof$BuZ3n4h9*1oHPsdDl7^S60p&H()T8_>O!(m zjJ}EL?ame|Fae-R3iR@iH9CZNYov2pWJHF<7I>HzCS^F90+*hgFY9bsmq}c3WTi^% zQ!wG;{j;iM-udI)rWTxPxBpSd7x44ev#`@n<%&dX9I;K$CDI?*^e!W9dYnHwMIPk2 zA`N}ul>%k7&IGg_$oRHV#3AxDF4%C4#6*Lq-@Zlz6vMT7}mp(BtHYXs^md4S6 zBHp4bH<%RBGSxzI^z8HYySE{PJ?`q&#XMiCzc-M zq_SHYY`P$3$(>Yo3m^l}fX)sHb}vE;@u`JoX<}H-X@jqC9CTxT4Yf_KJS-B@RyPf7 zs+2dgO=SGxFPUh}%c6XZ%BauBLet&v&GRe9XRF$h8VfQwm3dt?;kJo%%2B#3eWi+< z&Gp<97w^vMC674h_R`tdvo=fbusM-Gr*Z80Q&R zdCXfdFy~4cXAhfo%SfMT;X>^bXVVV%Lj>Ryu%vjph>MU-1|0xmJ0bO-1J=)gm(-6! z4THo%rvN8;b~n;u3`0|rcyp~J(i^@m{@MuuzDXsF(!h)=I$;#wTPVDK1Q8tsUkcp9 zlZ+quPvO!B4F;#1j7fo0tj#LhxP}axXbe+I#mMj>cy+quhd(kt1w8dZ6UwXWkF+4G zbXD-(b*>+a>}5Fos+Xan9rahejC7XNA6u#AzB+-?&^(8FCeBaNwn`i4Cr;|xedik) zZ&Xix%tpu?!30uL%+Y{!08Qt4UF`2)hEeGg^PZrIvv&D&R0C>b3ePgD$gZyS7qC(O zV{IS;knWB5Qk}CkOZo}li{uyL^k18HxANUK?xX`lFX~vz#m(Qh4)pe$tGtc{Ga<=w zs=-bS7dUSe2v_R8#}5Rn^Sb^z(JhQ$`+8iv$-?9i-}dRLKF9Z{fncBxWEXincOc0f z%9Cq&1wpl=sy)dqKf%Q1c9XFW*(eQz^yQ9T{ZSRKbFHw1fi;l7`^KT!PL&y~hB3|T zd-*m?t@p_jqdlRT8>UBiH^E-QtHVsZsm6O5<&roZ)pMKo^uC_6gGm{I$%Tb$=6S;& zny;1R4G#Vk5O;8hDgG$%sldi76`R?Yviqf6+rirL@$yBCuvz-(%(-TVV7_80!IXS8 zFRNp>^Ls9Rp0KuiAn&V4?gNd6R2q|aJmzd$e>>MRRs$b9+Ft%WF7*Vcx?$XQMWOr_ zKseS9@fBFc>m4m(yAM%GtuKzA-=Qk%cXlvJIb@nJkPk_5NI_SpYHkzbET(y;zvJ+(5l;(|o9GrCH9+2f{Ax zv8ubWJF@dK5`Ay}bmVNB%N=Hjh*W;u#C1XXTLpdGPND3v32lC9W&@j1C~j2yV^u|t zY$dl#7|+~&GZb?_-*X-?_dL#5h6_8#YK-9o&EtSR^_jbVr+gKK;p-_;@CRQ2+l(Pw z+)ARw#AnPv@B_65*;$3nAb_U!>m!C9X%*V%Tie5AHTtu*mIo^&+yo504(3V)7{wg0 zaLbZSdQWTH`7fV(4IGD?O3zN3xsG?^M@Diaj$M`&9eTY8G4skyfSFIQTV>{DpTNw# ztnUglZzkT98}xWr9yB$wu)O~5Vv_@R5#R7wWEj>-v3pWDwRkGQNjT5un0A469Mgy5 zDBP{X(}S-!f^NLik>Tx#>KO!WfS&%`_0K3hBPi@e{K1{=2}nnnc?3Toiy&UGN@orD zGm_IDUu*=V7}0E``GXrLraAq&^ z<-xr0rN(36l*`EEQ0NAHk|%I8i~qUX;P{nrr}R-|ZTf4 z0gHgJ3_IH~khY&xNDRazkPL~jBI6SA$_vor1`1R|KDbh0s01M~_|lm=#6C9Utz%nX zcj}v0Ri7AWUWz0c3n(R4#Xk>iXvq?CtFY*?`U3UOCn6vzONHhLqF#AVRIl*rTO^(@ z+)>%8SJx>;;1^MbM6gI45(AFkHBb2JE*gRn@c7YfQ2Du=RRB_A5Fha`D^K#*%TMy$AMeqoM7|C; zo96&zG7yKv;1Aja6%vDA9bUc4@Fj;;cIc28=&BNh#85*D*MEhFjH*=RUCF;(`32^~ zTpzO{4AA&}L&G{)cDUXJ-CzXzyjfZSg?B%0b|Hov!dsqSONxK{n|i^7=USNoK)5(k zsoGd|1?m|GpnJx@yx8WFfAu(T_WNb4fqzwMT#X;a;m(Y!w8l#nQHh<(U_uLYIv7aZ zvwRPOF?$I(59m9SO&VzCHr0NpY`GvQCUDRyRY>?s<>jx->OUXT1{Q68!;C7uM_k)n ztJ=)`hYnK-5k52Z0?!l5|7dwb30rpkL@m2xWY*9#)8bmNdB&>zZ^ zg?IJ$p_mxbiaQ!fr`*c>b~Vny;*c`^Hr+#a%G~h??-nnWPF&PZc&lh8C zn<;@MQB8nyj?*1j63@DO8$5Hw?$PNquF_&V7yka@%YlJ_#d6bb{hkTGv?*SlhhB!7 z4yk*F?ljt$#zYN`z>^JC)`Q80a#a!&U2|QRQb)KtoS4;gJ>w`|ooJpPw^~-7schwf zkZg)O=xQq`c?yC6Rn^xYb^_QZbLr?|?iTFTk~%0x)MPPFq?107{b*j3;k2c}_t7VD ziiUWR_K&Yl)Mj~*NSoVAvw2U!p;q$*3%f0|J_YmGZyGG)e8JeRQzlk-hJt0|3&mBf z$ciNwU)7q2@$T#LzH0MYarUi8_sjHdqs_t4yRraQ^cKUqc z?KjIy1MO-41{(8pCrzs-=Q@`RiM@@&Mq#|8CTvnaXe4-i$Aq6hA6>NfmAWY%wureq z6|g(2(2k)%Z6dcTzjzePHJsni_|ZsCS5QsfMb-xhN;Ua6!AULnaS>?Vv3@J1&{Ena zH2ndpwdUm;fFNL5ZyH}r;7CkeawIy-E0lX+Xk2;WGlQ7*C#g{GhoLc30a2j?-It(r z85#5MC9{>%o=}v_Ore@9BmsRCK>#UBAiQYPEQ9wWA|hwLb$=<@DhT5^RBkA~=$Ft% zj{U>KDs(yw9!nNpN6JI-K*uSVC>=%^(4K#bh>V8tQ*JP!Ba;z7Ljy)u4#p^xBOY%F zd7z^p0h^hB9+eh~XEMd@kSQ(rRdgl{y!!XlpLk8I=nzSvryfbv7%q9JvW0X3@k<^O zw@&P@3J8~?0YV*%|Ei8dri7Ir7_=Kt67kQ)HNWVB<~l|syrfbKO>AWcNZ zg+li*QCuhhqh=U}qN4}~5!`7#Ww}};tcWgAP6vGQs*qMhXv6e&24&Gj2<{c!Cw7?d zLr*`PCcLWvvZ7$cZfi;AzMXYEUsc-P8C53!yI1*tOMEIO6A^K)gIbI^zTX4>vfs)n zyu>Z|ISEp@-D=fbvuD4Eg)|xCNfE;DdAIv`HKr%5#*F>VlF(8YPGqTz*>7q!(DZxY zsXhWyA)n(ZDN+FiO35TA0Mg0@u~yJyia>>6ISO4Be}t!z98wmt`&+OxDk+Tr_}2BM zIL2L?!k3XzEHB4B7ywpOP7dHYiRM{AU{hL-9!WL;(d&O0m7ejVlycfEZ3g2b?kmMRAij&%hZYa=rnH~d|G>E?EWazMAVVHq8xd!=+tgQb6t$0r^iSU}VX>ELntH9^ zIiCaAw_)(G3y&R)%UP&EC%ehd;KE7#_zFtA3KlH(Kha4GL`=qjbhbp3F(C0Q74A?Y zaxw-`&+cHxB4;H+ul!HrTk?DR4#K8E1ZfAlT12BUAks^+gYL~E(jv>vc36KZBFsaD zd%PDJsRi_udvQq@cPw$LtMxuaBK;%yc7sAN(5L1*Wd-StKrB=lW?I^yv~ft5CoiPm zzCJI}=IKa)=7^PGU4pH(?~tfX?tolS?Aydk7OKX2J+5O3;;%J7zvt+UdS2OkHTSbY ztBJ}BRSA=4$|fm&2Zfy^46QL_PA`hKw5DQC#p&tgIeCcd&c-L(G&pg~&&P&$93KjL zODY9*lsB&u(1PE05=$*%&`R3UXP`#V#{dX-Ny>^Ejj_ySLYy5;xC2xi4@+4|THny4 zF%H1?HZ9;hBpQuD0Yhi>Xbdn96~MHA#1IFci>cJh$k7<^VS~{aJfet0#1pNvX-k*- zQ4UHhlTKh&BPEuR>7B6qYqQ!qgjwy(idijg*{nv~{;_`~3dq||GUD-|ctrm<6}2JF zD!KDYZ1D^CnBxszz5L$LclP#k@>bg=HOfG;ebM=Y$(h-o6x`I`JU_9+oI$@x-!Ow# z&?5cHY~w41>E%Pm1 zg|-C!HNd3z$32W%Q=hKex26K`x@NCZL0QRiaJ<4^saFajM(Ti*Y}2j^irznAEZ0Dc zWiOO|3Nx0s0Am@?DJTUomIE6f*6lFg;vDvRYKkJDM^7Fj>#bFF;g2|aoN6;2gHVL} zWWL5-$1FjcpuJYzLYH2}$uF=MJ__}2k}mJay-UlRU^bF}C8=0_h{5+>N>(MyUHf{K zkufkILvXR)eau}tKQqyGY$^Qo`;Do(CWe#vC#CZC`0w)V4>ti$JjnwBwT$z)T*q4TC!O=0BSKBbmM&PFsQu> zK<&#y@kYy%qO~ia_A&sqM~Ol0M0W;xmM{RdrYs0h%K<>G%AbSUpQUOrs7+e}wa^h- ztx?9tx!@ljpb2wtM?;aW2lNn$Iz}5DG-#Y;4FTG7#eJBxu{ZmU#P5Uvty^Z`TC(S^ zD}Z(s0NRZJ&^`cw_ITQgU6|pnD#b!-{bLGC0BBzj09pwc(B8o(>_C8)o(BM0wk1GI z`wS0g&;BW()i;t80D$)1Og6{LH<5DG0y;Pd_7oE;@Szs=2+$}vJzX15 z^DzM5t~J*OQIfzpzZL78=oU;bCH`cPl9~fO=`_cXUD}W0;V1C$K5#BzFX-ZdShf8Z zp-(>rP>pfmBtIfW5`k+H0w9+HDZhvKu;P7!4-nNoa`-7bxfeN+7QdQ#s|$Y%E(AZ)=lU_kXr;l`jta1yBlqBm#qjztt0q4Tsj#MTKs2r5S^k3y?02B%m#&g@Lio$dIdR74t{{QKPK^RB81@; zunMl4nO%yKFzKFihEwF>oF|p}pnQE~yu>Bv=!G-$9y62^a7k!>APO-UEjkiN*ktZ4 zjm^gUv^dXX21^IXE_2;E#=ao^%F8*p+T_t{cK zah$w#FM5sCTF-Sc@6oa>wVN62@&r(7Y(GK+)xsj z33Z-GFAYY;V`iwm={x6g(tHDG_fajqaXiqofX)~<*W=YSjt$UD{pPwok8zlk^r(s= zf8?!+k37eU)y_;?h=TZZ#rHEvH&Dl)x`BS!%tKXbV%|w#FU1`p*_t~tw>oBys8SnF z^gNX5?K3nn@0p6xm)7p0;R<^*FUxBQWncsk3uOAX*sG0{;@Wgt29ndYX=N3VqmbiI zZ{ZU22L$BiL9*-Zkoxshg|}KGUGD@=>7`E9>1!=QH228PRkvNbze%CG-cZ1>@9f=L zpnIj+I0#o7hs3KsCN~GJtNVp<$0ZLq9XBae2+wtJ2X|fXeBC|3FK0DP(&&ivy~hK; z?K#}z-BkCYJ)~DhSKaL1618!_1C!4SJ>uO%F84?_>v|`Qsv6H(COi4ELB7x-*sgzEK zCn!gB@a0j%Qg}lK{ka9EWTx6;bgRdg1#7c%JHwwNxLK4v{E1$~0`tjFKw4Y= zDU<$!Zxs2Leb@Gi$^FK3uunenN%puwmUBm#>5la8W13(f*xibUCm3;5WxICdC2OjG ztSj`)+H9oSX~f{5RhIc9x#g)+c;)%8Hsd4CHtSD{c`gRmEHd$8RNV*Wp|q8WBXlpn z*iwGKe>muAkL8!mrb01&iiyVtvEh{(xigO*b_SbQ6;^h1O$*X_WsuW4?AjE7ppnH^&|wXaL6+U~7@@ zwp&sQScj%k%SdGrkT(4YkZOI;uK$kQFuZF_n zpxmA4fUO|)+4~zih~h^0Afw9NulmT;KA2&+d-w(^F5wyz;T-@geSqU?6REB`1)tuI zgmxgjVG#L-l+OO!HsFJ~uMpDN@fGRp;F5H<7yTUtzOoWcOX%j5w+u!L)1Qntcnr5( zy;fSTUz{>1N>X-`ANYq~Q0-&n zn==%4b8>c9Nfx z_Hrt1Ik2DVfq&Y~JC{FnuJwwO-(0@r>Ng!Z*vq-5i7)6f@Ny1$K3u=J?B)CdyqxjGUQR>c<=n_>spsRm zIkauso{u*6NqX*2gZmZosXh97TCsZclGS?_ijEmIE?&m8#zv@pPkb83#kV*rD4`wv zw2)`A6Fc261Ro*8W~&J$5B#wvC z`qXFz$tb(}PC8>wU2^{Iqj6t?=+%uZ`1&lS)fpxy-tKg0+n;gcP~j`g3-*dZQQ4nK z2j_IAB_{9nZ_1~9EJqX6!E?wiv!QU;c%MB3>1m-mkj{zBS+tgDr9G<`N4Bj!hD)z_Cfb{4)68P;Uu} zkn5<~%f5Vn!GHC9AS=&~rMQK`@6ytqke#xstt+2ZOY++U9m4WH<2QlbZMcSbl_i`W zx@ni+GU1@I{c$^AK^(z9CwpOdDmE^_hVK^UOIeJcG>h+9MsLx5c1LkHF;dW9rdl5C zJGr_I@>B4tfpN6p@|lL;;lK;9a}L4EggZg@0>A2LPHJ`i$CYaZZ(-ewoPhxll#{;n zQCr$;KLu#@o;u+!NXDOwAGZX^kobBW2SGVomk)UL97kAfO!n%y^BFwVnf=C)PxahC zHAEC8&_b5YcerAazoJTO!w_04Q?2g_m(p9YS=9>x(r=f_eauq1zsL64eH!GCVEg;Q zCg8$Ylf8%sw=HyUdU8>za3m-w<4+(^;*dCjxu;hy?CNpKaZ@e9A$ zs*DC6-Db>#QwTqBgUgJ^O>_PiO9{wef~hM=OBUhiivs*+K=}z;uUzz9z#d?eLwvmh z%4HhP5LRXhWZ-kw!K^}wz7-Dxl*&QnC^}<1KKiZaOKFU+G?TBmHY>;u3do{$TfV`U zKN1uNvD?(I?Iqj_^ig}BXHkM9{A{}@+y^}GQ9FarCR*b!sUTd(?}p0kY5!Am*R``# zP@ab>@2$UVNmqTeBxE0k%+S#b_Ew0b;ZHm-UVVkh&}@nyW|iE*bQ73|Mc=~CSMtjgD;*vxW3zS`Io`NTY|za zR*&H4>uzwvqv1_Jr4V}!=b zB7Oj_H9)sqhAnQ@P=Uvb3AYvIG0KpYGo|wU*1}~gr`S^Sob1-1)NRPhx%Iaq9AxDT z?R)cS$;$bGJ^A7bT$`=dyYAAhYJt^;L!l(hoW#no_bITMGs%+0xRro3o>x~NG-Qr@ z9Q^fGR%qe;%=yy``F2bxk5;|?&?qAi8AdPLp=*rvZ-I6i0K1$VYsjKjntBkea|U<5 zks6T~2o#PxSczO=5Hajj5?ut^p{p%K(2fI20>Vv#4hy7LuHKAH2^v>2-(x3?02q*I z-W6D6A0uRV%uxSB9YZTa_}M$90OBXo%LJkcTOw{zhLW-FegR}lx5jEu#T$SkF&bh} z!~uA0pry4#-YJ)$galeUq+$lV-}>@&Av+Lpjv6%uUhV;s0Z@T>;5G)?ZN{iom#By3 zKzPGAgp|umNwNW~lY=VS@vAfKjZ&t^Zd%zV%M~{N{JU+OJFazb8)weQ=P%kgucGec z5XL21WhdSUN$fNYpJ(^IjxtCr+iO;hHX!FO-?kWY0kDq5?tFOX0qZDi+r8j^SLslmLO^C}*O=k5x3|M?Xr~q-w7?4XI z1UWtdu;gy}pDpc1G@{|B%o7iGV=YQP1@Fcz7-vN!!vZ%02nAe=3dO^(9#Y+NmhdL_ zg!UW6aH66r;Ir|$z({NS!6isln_u{M%`oIW*>DmAF8wdR*2DF6(O3O!l}Tae@mYDs z5>!MRJnwt8jQ~vh6ag6M5P3=2C32txvO%TG!-rY8SNq|y_0QSkyr*;{v2cuLLEo~F zc9Lm`F?O6hE8BAIX<>^#pX9RBY8Lny&05ymP>d#@BBY}&qK-|k)i;7-s{_A(Bed>n z5L&J`jV^e;G0^VA=5Yk!cuazW0Pd~oXcML^T%nt>Bmr(`2FY%_4+i=Dg-J5&DLn<4 z>+x{C=^?eJYkf!5c9n)U2y2uomIfJj<)-n(9S;tEgZ=*WjVcm zFf*hJ=6cYNn=WM>Z?+D;B89Q<$2F#iM|VxdYK~#kY;2trk7y^}@$yOeG^+Xx-*ua2 zde?l1z$ZyZSG`C3!;a7ii9OTSuls{$6MA1)Bs$+M_ic*pmG_#Ta#+aL3kFi@sfQk|KMJ4s+&J{N#*RTeM0Qd!aL1)HdC(;k)9X( z@{~Vjf6PwjeOl#yB|=lD#DgPMuIVsUzA4?VD3giPkY%)wPO4^kP{UQU7?d#jdo_hU z`<`%Ku6zwuoKd3l`fpXu5sP$7gBIIn9(vcYbtJ#sywDxjYqoGuKwv=!`*!olqd&Dk zKC8Nw)OSH)K62}WWpy{mG8zbGa-e}hBBW%(~|@E1|ezJ<0TWJ$DnkV_;m zFVau{a;M@Ky*eq4iBgXxL{b@s&K z*WA{QOz$M`9_-ff6PxXM*zNbT(LUPxli6oGtM^XM^2(CSA+l%UX`jAKvXYp0>{IX$ zs_zJ=%6`i+qZ1{0L1{OG!$@SRK;En9s{Na}azMY!fC2IB4)Da5KSfC?8-L%8 zNyttkel_O;l3h_&_!5pOJ~E5!Yrc+(K2aW^^a^>pxZ=Ob;l#a>U-#b7OJ|Q79)RJ- z(%!v}vIm=W4U{u~WqV=tS@)3=UC&Y~Urt6PQEFvN_UU`#gs*0fKMU=}`WeEr=N1Kq z>e%>Gd_x|a;RfnwV*o^qzbUp+@g+HB#Z=eQM!du{HMeYc>%b>K4KfA7~KY|a#pScH|#M>36eM92i z@*)o-yRPtMLL@?Vu}>&jvWQqAElXhH!q#&60T%ZA2N3@$o|KyMQz9cMRXNsxVd*(O zVF!@~>_&xAV+@t#ks{p(rJH?sF|vrBwSD|!Zx`9g?a`HG1NRZkI2hL6F4b}VD~0c7 zPsD%FiInP~tKG0%9FRkGOstFN_XEMy{ow(>-zu!5v$VgJJCSIUm693zys3{j%V1=v z&qzePyvmiwpfM>@v`4gN-a1E6$}hWD-9h!?m$FSdp?xa7x5uot%3SrugE!@7iygPt zYt*0aUmsB0`8=1qW^hw>t@Z8W!d+y!d_Vvu^}J!Sw!c91_Eg4R zyTdi%mIGSG{OJ2Iubql7$1AT%S3;DZ1Nk4g+;nz@=QpB{D1`+(r7nZOPtb9)V9R%N zG)ju4D-3>ArfIAwdXpfOQhmXg25YreE&YG7_Z?7CWb3-eF@T_A05O7~(jZY$kSr)7 z839E^KvY0cK*=ph3F3eRX>vwI5D)~0oJJ9$i6Tj|NRxAu^V?NT=xX}B=e=jnoqN~2 zt7g@(%I@l_>grwl`@irP%kI@MG*Q1u=jT{HZ^v10r2f5(BQC`v4140WLMmS-M^|#c zN1n)3|0f~!=vpI9-78F`rEeQPY4wDMtJUR}huC!Os65tPT(D5bCAzot8%MnGu-)PB zzMOqmuI=aZi!0yj_Atq~YZZl_C<$i zh@m-^1Y6{*`&h*cMo%r1p`zFRAzCJnvAxHm!5{dy{=&Zx9T#hVCQMwyh&dej$_=Y{ zmjzJ_Yut4rD{$V)z=ZUraahIg$Z~*zR7{T%9;0FqnZe|F5KppFRcfn}Z)HpoXE=x( zOdq&!%VU)9tkwTbb;3+{ubqa-P@P)PptGi~(aDx(5r(|?t=S8CPwUZqOSei>ET%@L z?&%bG*o!h%8#*%aN zSkseRYKC=^V|3gUG^pa^HiC_{BNN%!#blI8RG>yh@`v0AyYZn<&m5(!>GCGVxQ+Q5 z%CyEQQ!2#n_=Haz62G5UtnT0`j0CXRzI%vx=Cm+I`?H}F-;4*ESjSzeEiIYU`2L(QWvkO3v>e>Konlcx%D1S&oPD0DQS;jC zlJ~ilLQP$}-p@vQ-M8b^ckxVY2}+c^*Oki2YssDebs8U8V%rij5jXEqZG>J({S)Uh z+|lrD=39xuCUok^!7oD}7N&&TI0iI(^RLY)bvEVORo3?><*k-1Jg?_9AX1y(4r zDBL^Lmxdd!KfjKgUAi-pC(9`I{rwwsHTqtQJFN&&BTyE%l{z`|{3L@DQ5g;Vdh-H=2Z<`eRNyCj zT-D|zTH-wm@her&$4uYCzmehIxMmCVrTdkdRIs2TETc6MSHZjn_A1 zO*hKP)fmP2qJbGP=E!WNYf}g_YdE@ot7wlm@<7-ke>P#~Zu?=*ubl@pW`V5~wp-9E zKOFc6^Hk~ev<3d-6A@(L+(&725O*(JeBCt;6&8u2C%Hn7K#Yy>))^jMFGTI1a2Z(MAS>oFG2m!*{K@Qg=0l|kavVJu^Toe%gj!qT>nrrPe3@E`lh#pGW>nhIRD7*!|4Zja}viP=F(Gf-Hx{LNDBN-3)+YmjJ zB(?tf*!V~gUv(>9N57fie}|G;un~NX}g6y;pLqdmOJyQ=xT~b^%cAu)vC)d99~H zN)=_vg7>=vr{Ac&m*?8{$I8=xmsYm9?-l1i&4M@woEK-%x-Cs*SpA_9ITH`zX5+!1 zx05)^Kb4FPZAR<5J*Jam3m*x7kVHv8_a&Z@yJN&!SEn>H=Z)5_#3sWf{Fox=Oj}%f zyDMcR@dD=how$42U!Yn2nYYm6&p5s=>Rn%N3CDceW895EJ9wf-jhOiFyeiba|AY|1#7 zX}C@6cOK!;Ybsk(5*p*(&d;OIf{qi_yR5bIg9o^+nbl78_Hs}!)_AsRet$SZnPR*! zUm7fLp-H8T%2N(vXq{2B+nuh#J>`=-I>UTJwLd4J+=fmoRp1eKPgjO;!JPH)4s<=0 zIi^7iI+lryVH3@qXR>_buyvlsa_J_s?QMs}33W6ds=m`%!8iDemq*1jwF=qRx15zu z^T-XRr~GU`%$$t!w2$|oq3GPY-8f!dSYcv{2K_?0U}K_;Htj5)o3^MHANM-lyQ3s& zZBE@dxWm9J+e|#S<8@Xr@4(IKrd@Jb~$f8@^IlvWv8CTcZ z9cnoC{OW>I@tJ(Tl!7AE@1rG7wY$>FCgXO-HrJP{CwoX}we%ZrW)ZVFSm{^cf3=Re zIL=v{$HHYWzk5bcXIN&bu*Bs=+rorKo|eC_HYY=#$XNPz6=7&9YoU@;-D7|^JAFZ^ zGU}k*DD-3l^EbRsdHlRmRn8cAmc<*y?BEg78aM$UyWZ5K#w*S{?hYKz)0`<$!X~-c z`%K}Lp32|-=k{6HpYy)6`XFPn@u6H&wCiqYm~m`zm5d(yW<(!l^GB!s1~YTBF0qXj z+>A@&r_>(w`Bm2*Pt}&8T!f!u$M5U)E!lh#p8r#Hv1F!;UD7lE@qSUYa_xdP3r~Oh z>;n3qMuFuz>g6vZUIk;TRqDXkR3{E_;bGeSwEfVrgIOp&Cc1!YKkfb+hW2>JTZd_( za}_)F;)o-&Nr*YP?ff(S$j&2-r_jod-n5x|10p+{nN z(kG#v+UK)rnX%3A=s=&2SO^gC*KjtKP^y!N0Q2TEH;)q+8+H=*QKRdMNEC&z!ZAjV z24oQv2BKjhr^tZ7se3gD8f_W+B7rOneP@nDVL~8qO^k9BVTc<+1}Xm<{8m-Uh2XyJ z>SPMW2Qb{naLxTpBE{KPz2o4j0Ru^a0InK*46r3rcW`7PTX$gEzrM&JygvnLCMI0C zW9z0uppbxlLhi#BNI*FNIAU3tL&VbHtzz%OUme80t46dV0N7XalAR2rz*bts;`7^y zEYFY=q^P>e9CsSoF7wP2SL376l&)(Sn*h2MH_&NbRG^`KLIkx{H^%gE;k7>5SzS;< zF5o(H;aj~}*4^jy=)}rXh^;`AD{clh7ul^V;PBz?{I^jpkCE_Y1{YFOs&$ym<&|m` zT7M679UFH4zK4cn4=tDMz9FWc5=!8BW$+j~Dq@(pInqa|Dhh{Ma8i&*PI+pkg}RU& z?oKd$(3G|Nv|u&BRW|gAWK}-&N!pBiW-C8(LN!Q9rzvMA!7D&Km#y(osw&5!RFN}1 z=%w;@pLP@w&2Su)gd`*_G2tP~)P>v8&0a;wRkXvbhY@};!_?cXD6}=A8sqZI(~(}| zNk$vPAb(%(iY9X=nxL5*3PxRgFC}%O>ktf2zP+nsp{Hmx zmud@}Gj9*wnb?w55-V{>uzc^N#L|3D@{nN{PQ}uSML>#SDBWT->6)LOPA7WGDJNMn zmn!B^X|0}{WX5-Xe8-QG9|hcg&YazN@5jIA8l^9kR*I$K>=Rpwrh0wnVx~>-PCKc@ zAz%i9HU?ASE~~OpRi)7uoTDf-_>0m(Q9x0yTqObKwgIN0`eWQz zPvs7^4_AMBrX*$-v&(GpXiS20H0BQl(bv%Yq+rv` zLx&rmqF?`5h2^K7gy}MUtR_rQSa;a;cWbvkNbcXME@uJQrFGh7 z7gwygR=r*xRbpdEM&*&<4*a&^VcnpFUERFHA$s=TTl!t}MJ#1Q?MiF!^cV5J)eu-1 z8D1$Nfw9}>%#0VIR_MBIWdR~acViaD6cLgdVxN#JR_etlLb?MGNFnYX0`0&U#tpm2 z04dKoAW=wX*ge;gzuf~8wg3;Nu6t!1cF$wd zR~A}gXr4XrDndXx0SMhOP@Z|gjbeN=E6)DT;T# z1t6R!F{V?2{>3vZ9(m4GP6vv>8>9x1`ZEFsjY3>?Xz&Jz@Bmpvc)%r9NjjZ;S=j8K zmxY@`M5h~1bF*uQr1wiOoF2;*{$4&f;bK zXs2~qFEw{Ole@BU;q>641ytqFq4#mNGY{Dr=S@+XkJW--2;no1dLmbenMaKewJ3y5 zemX=WE+QR&P(||^`o-&F6TwTurHZ$^cg#|6Y&CO%>J0tOv=7YFOXJS?W;a*I8h92rrZN3 zOx=3BhDJvWCt3$}(C|pPD3a}xuSk9H66?vIcaC;z`%g}}n~zb5NYR8QE_|t-os{Hq zn4k4IJQlXdkqg%^`L-zn2DUOLj<5gcPJ0FgFWG6c&#m>tEOSrJ(bPN%++jFH}#8u?WHy~tML>|)Al7LYAnh(l@f2z9{io8Y?+;JR|=IaoFe%n* z=Sr_BALj9l(si4GnA!z^ZRE8wXx@SOHq{HvnH29fgI2V0iQLsQsuTf-xh?3NTsNdx z&v91mO};4ZCo%8Wpv;ijic9sX?3Q91D7D>|Ep|jY856FIui4Y_AYrGdjMEb8-DpJx zB*A0W|d zkirB)K>@;tEeK`TYZR%}p~VpaKNr68IDki8pRvEVbG{_iiOBNhzL_h1u^&TU;GPmvJGlP&DOlt5*U5$Dgs*nGLm`2}h&1A~wcuP_;QIAgKf~uLvrZDyHX@$>WGs!65`Q!KYcioZ3BE zaMXbru|TBp%c*ClkzYUHqO*&wZT-k?6`4eu&%hqiUruEsctIG$3F7U-eUY+1a080s zTiK9T7si|fauFd~124Xa#~`M%aIHrTFpeq+3`hwk5?sf{dQoNuM2G>J8F~)~bRZ^+ zP`%iUb7t#QM^ZLVHgyVe#h*=0^U4}9k4%V(F+>jD!tV(}iq0*ZT#Z=7B7+c%D3EHyE>x^wy%KTTSQdWs$X z#hCC^Q*RxuWS5`*VBn(O(#QI@X!V(&IhyqNh``Fuk48qG9-4uv>Wedfz8Sad;wnv< zZI9<-c;%Vxx*QX}nyR64J9$yA!4W>8K=#ew49HHI}C_DoB&Sb^gK~=mD=HXqDc?Yn&e3zF1z#-v5cuIxD@+i2Kh1p^B6VOp(~tB9{U# zJIl=6B)!p(^<8m>n_(qL$=-<*!XvTcl9Aj?68vKEe%gm~-w$5*aJHr9hvt4F1HpcEo&w=x2f+#?PEF%%Q6{u&y@bF)2{{ZbH`W7Z@WJ{ zR*{Cj5NF4V3(_uaXz#e6-o>sGgf=WKgGr)g0^1Vbr)6n-dZvBOD$OkKk3j0gy?kEH zhtrnAx`Ul_*%#>98Dnkc>W60@Yg%a5(6oikG_jzZnZeQ+1(9x!CpA_PA+(j*`9Fez zpDGmq>hJFb!7$?f%Q3L(ks8+j4j`CNd-zK*@WLAi11CH6sSO)x8p`q}mTMYSHrAK- zn%H;;Q)pDgtBaw(pu^?{&F;H0n}S(d{I+xf+mY0JT37SV8rM4u-|aF*e+X`ReOpb> z(9d3!hixG=vlJh1clQ2NuWI!{_kvEsE6@RrYv}q1LQMf0}gs zM={H9QI@ILbqE*$;vgaXmnuMRbC-?otigPStBDe;)kI&r?I7eY7!LUxv)(*(PJp+x zFFsWNCkE0q@qA4HO+cCxsfRCE4c1+`O7~m!y|fSXv)$dk=El6J@XP{UtN{LDeyW>i zVe)Be_R4H}93*JsiTdop-*9Ue*QC3;nAVr}sS+}eivl|2V+~AlO0m^;`#K=m*?)r6 zw7H_dXR>I1&%W&%zx`L!@vk$D#y8#@YvY)U6BQdy4)<1mgR6$O3r5Ut$?q@AGDzXt zG1}d}Dbq<&YQT2EC^;YM*zzVig=1Pp?6IXz!N;RzD^CTsOQF*;_a0kyYtKkG8|5~u zOp@q$aw7;O!{by}BgDok?oGP1UzuHR_&@b88;O%&r zi=jLbU=ZCRk|e=;VBg!xCiT&g9lII`qoO0;=^1|=2SfDioQv?qckNHrqPVGSXXsr! z3}$MpG_a34uRR=m8_;+o&)N2T+xWp*KFWo5e2ZqW?{=ew8&nf&bE=RMIo$UugMR({ z5to~mI_}KrlcK{9f~EfGbCF1xNewwHDk}X#jV0dWgKnC(vr=cCQH8fTEg1gn*?DH# zo8aLud9Sz@r_G)wlJRe<-WZI3SM5@*rYFnV_y`cENpbX59Jab@r?`l}5l`V!!1@75 zS>p0HBj9$5$$uuyu`GSCqtrlw5io6XVPVO@iwAV!nv0^o1j8> z8@HqD&~e2*jZhC?W^lSI3z&@8d(*%iDG`7Hce(~P`2A=Gy{9igh2VeIU^VQ*&87$H z2*bntg>GEO8Cl|2ceAoPDhDb*S6ZLXig%R$*#E&h=SQ4lJ!#;F45(^SEz_tg@AYuUs8enBXY#_0Q z7=rw;aG6vx>=5B?^dFKJPxV6g7}Y95f;m>Mjbavi_4IX?SBvkH@tiM1og35xLY(sn!i3 z-!0@mZ5Tz47Da&BY3T*pmP-nuETrV41YTvfSUTboVxd*4vc;*cV>SOxXcm@M|IKiA zO)5)tcff%7UqrK;CAMd^oh(8Ks~nVMAQ8i!p`zQCIu`VL$d!==J;Q}5@9>A`5jrY} z)hxuJPOoD%TL1xiW*q@qi$e|YY$K*=Qje;d@y}q{QkB*boq+c|5i{JwGVCdYk{0V7 z-x3;jM=k%cWxs(2nD7pnSl8tlDfo9_nuWic=#|f6c`L@6jiWVGXahCEQuSwp7a#$* zZl~M-O~CDvVgWRuzgnq3D8Y(YVr(htv=v%qcT-M;5F}RttCFi!?XmM}A!%6MZTpT1 zj9G6PxDMQR>&wts+c`4=yMEcA}Hl4#T+@1SJ)FIu6NxW{IYpX(0OV4Wn_{^t7V0f*#h%qPphIoueFCbc5!UZ~AQ%~W-Im#uihyyati zza?e?%5BvBhe)Y}Lo{P<_J{T#mk&+XRp#e3+^J_u4w#lH$Sn|BDpCAt(cdY$Er&#o z6)w(K)VaU4t@O0!(F*-mf%3%<+4VG)kB9sO7yQWRu|OSv+5peATr^rO4}vOjUZ73c zBx$K{n3aX`B$TqT1~S3S8wi9%*42!-SrlVxorqrvgo@g7VdHm~ffWHpEkh}O49bTX zx5A3lU(~L$MScV4;G~5RDaHV;B%rRD4&stlB&%zfmL0kUDA;m|j}H2^Lu%3hPBLmz zX@3%u4%V1Da*-hfbHwxn5I=JQP56}@f62J*I~n#dY?6e11cOsY6HsT7(7Et2^gbu2 zbCqX3^Mv^12)yX|Au=>BjS2}{3SR~t31o4Bz$RL-k=ZTH90xKc1O712yU2|MmFg{0 zY8OV2XZ1K~k;+w1@i3TNtv3{OFhWhx4VTJ4;5wtOgPkn;bAmjqC@wPT_VQ=0e}A**#YzHL2bLmcgL5kC-`pc zVxlElATB9Hc+lk}R7W<*s-x(b{IWJ;N>%vkS?j0;YRK_hdb$|LO&QUY_6rBwCozA6 z)gfDU%e*+-P&`u~wP1U@WnR3p>U{V8{70#IwlCd|C}KdDhv_;Vye{yG0KtO|2L^7OwG2dSGFj>*2oNcurU3_j6Irh zv1MiE3(+<##(c}l)tH;Hp%zo0sUq**3}`ggFDwwca7U40>Dpn&9VL4Xv|dZG3h5hW z#P5rGMxo`K$2#7r&FT@?sU~H7yvXh`q)XWzz>3-{2J`&Bz%G7 zTDIP9}_N$J@l zz#c$ju|l^57DcJ^ngoeWk*@kL6e#5C)!#qc*@goNxr zXn=k#T8)FRd_2?Uxt}C>RLtxDIkRfN$jW*%DZBM!xNW*{W&WLVxrOk`02jvZMcM*w zHc>sJYTO0gu`~Cln}$a5#+K6(&73I$9B~37lm>_X9VkzC7i3ffOd6mq%Vi!CtY~%O z3kCInk@4o&fC4wz0sH~~bNH#1!7{Zv}i2)8w50a-p#br=h@ zfRQviEFe$ZxbHWm?GZnlirE})A+4e(KdGFP^nY2saWgSb3As((a{NCqGVG#7EYRKN zmc##M>l)q$_aebT+Mlvcl?r^N{Yi`n<`CM0drsSNBxr~5V*Sghx%DLQ)XOP_z;&0G z8f$%Y64_=2R9x0uAfZq523|)58wpd7Y%|hgkt&EhBblvd<~;-u2#wZBSppPt!XJt; ztm7zCvLAx~#IpS7oemFIPn`Rvf$8~-5~iJt{dGA^KQO!iPqC|e|%t4#YhjVS7teLylKfQKJGX->!YbOX{J04TWsFk zZ|^Xj%F){*^wlqojK8*|=Q||qy0L9`#-BfUK=8ueJ=*s& zELZE%E>HPIwVm7yLhDll6Fj_KN8p z6wI{cMeh*Q6DtKrW=Cc5LVk>A0|SXpeBy8+?&ue!&ikp7G~gZ^5l|1FQ{TcnT}PwW{E(E|UblmTfe zgyDg>KdFxrs3w6!nVh7vhnF0t+Col@sW`U{Ii?T*99bA@_W1}xB|#9YviKk){|H7! zCd*Z75;l4g;Gzqg<9ZqG3=fkt!VF5_&9ceu*Tt5c2~+A1WMvB&M}gy$#7qc%br$&c zfK;V5Gvcz66~4fi{mG%Sc2XrQe0^TiBI^R1CES4*RO);kax;7>q&hzAm3fQK6_55$ z)A;4Wm~KXSuVbS8STep4oy~<4=M67)Y-wgVoPFwk%KX?<>E7WoO+WpK0(A}1xBoJI zck#cTzT>dV#;)ZN5(QcWP+z)YO zoNt4(iwe?ftWCh2ucU8(b-ml%uq$pPw)}T%aelZ6CQBQC&YswX|E}u&4f!<}{>p?K zqBAi32XO?8qAJh7;7R<^D1S0F(}sHPSza&yxZ%#(g3j!0FZP4YvzfGgiIeXVZl3KC zV}CDPk)Y8|^Kt0Y0ZF4l+tvm?&%3oW&Ns&H3kccRc<)P;yLMQo^g%uqtX??Y&x)(f zUA%e|Uywffpx5S}E~i7z^=Xzgp$AJMmHgD!YO~x|MO9~p65H?-S@H7*qa%ZX`G$mi zm-O(Tl4_Xf*GvwNxms?zN`c29n0Wip+}AsvU;D2+5|ukbLxHpYni;H2ERoV!q(7%7 zrN7AgV;(=sc+9l$t&xDHrt(~r(~rtLjj(R*WWBeGmHK4`Gy@%pA;x*io@hKPb`UZAjuE{N8FJ%@FG1xtc+rGa4ZBwBF58*CWdRUt?) zEV@n|Eue%-xB1#z=vrjMSpL`#V))hsI+9y}L?_`m<6Bq}yEfIOayTGG0_dP1#a0?^ zKu{o<0j$$g_hL`Yzr&LV(}83;yD+l`h!!Od{(*qq4afuuD#1u6CE@v1#M=yvtEQStaCML;&Po9MxI9?7l4exKQPI!l@uVP4K$y?!x*khZmZ|Q2oV~0 zjsSZw1R;6r>k=M0Z6L%6>}_T6gcaqUIhO11OwCKJ2a{0ikmAevHwY%yIl>`gw#paS z4@sW%AgD$bt2nzgG>B-L56wXrEz6L8D>(ngZ{BHc^t)z2i*o~V72M)H2TaPSW~74% zBHB*QY%NC`lYrBZ9}})5zhjLtVx@#$dS+&;&^AOU1+Xf%$lIC7aMJSQ9-U`EuEMDL zgtD-69Tn22`YaziDkxr6`s-bZxxbRN^iN!g767~Eh2;1j+u0{@8!j=QTrDvhT9+HXsI2KJ4pyHEJ;E4&f+F6fd*F)d2`80DSaFsVc$6wl75zQP+WaHsEp~muvF% zIPySX*fUi`j<}+kB|&Kfr1G-i_bW@>56%C$U!4I#Sm&#cRLj+--nXbR=Zq~+{iF?8!KSnYQib|vdWBtrJ!$B-2& zJm@UI;PBXlMr6~nW&58Zx0$H{LY$0_Vo37Ku|(Oqxi48Wj$yA|D(dYz3~c9^>Ba4A zOFYnu_I|CpLzv2g2cJdnxi1sn195T#6;>p1GC`T0AWp`|<;H>kr1a9T;U5bKIsOm_ zn;PalV_Sex=XgQB(DDof(x-v+9I+Qrj>Wg-XTkAj=Rg5lqUukc)V2y&7t80xVZw_^ zf})3fP^WW%COxBfdXdTVvH={T#{45`PU6uG&V0eg>;eggsKb5#8U*(}rv-3xm~qI6 zSeJ;m|7uZ66f47L+FtvKKdD7$ZWx`X{yqDfeG`tD$+n1yba#F@9vgzCux}#dSWM=M`F8$Wi z*HdP{B}7|v(eX~g_ZrUVI9Y>ypPlm!mZf9!vUO!OOEWLf`=k!pciN2kzADnr-4-6# zmDp~aT~wOi(oX#-y{zj)eAoD8rK(z7@7?DSVZk)ZiK7I1F~;6+Ep-OKf*r1qfbyEO z0>G#MtZ}g@x@ba(PUMq1MWGDHERA=Zec5q{;4Iv)YQ~KY`l|N?ut=-2725p}IpAj# z0Es>cXdb4RAebc6`T&tTBNhCSCZEj>X6@QQ>ZFfNz=s_xX8)D{!}toAx!3OwR%Q}? z1W4u;cYiH}{hy@EB*-|)MY)QS1k`}*FuBj;hO`1X*6&Se9u()Z8tuAF-2u3P)MG-T zS?K%0*zk}8w|}p-@VLVPbMWDtana*1G3Q<)7Pg32 zbH(r0;W}rl%5M@U;0t0x^7MDvV zdRPMA`dnmPh>$xDB|@Z;2EP-i`f^OHHyQ!u;4m2(kY?IbgHVboOStFX_E--J|tkP69Nl^ienDwjBbgr(*I# zQcKvB4C{UaZPDfuilt_0|JK@PLxFjznTl`h)Q zWdFu3(iQVzPlYZM0`NAlh8h@}Jc`f+T?jL^>07ssHolLGKXKu0^#dL5@k-$KYSmK^ zHFweXHpR8u-KS@C)4jL%YM7;BF}p@h+>?@|8-{7uoZM`WitX4zBRYRe{ksVl_dEaZ z{T5C6^YbdQi&K4^PHXd&9Zs&?C`C%p2ZxY1vqIc~lq`@u*#l|c2UU_FVG-MvwM5u0 zx1t)fzF+CuTV3AL(caXT+vFku2f`k&?uTbFl(lzu3$2$HF;U-3=Q6?m0Ew{lJ|dyC zgh1Hd>sEr&{W#t}XeJ})MaYAt+OZmpx3Nck?{48`dC|{5)9n^J%UQB_ye#~zc3|l6 zYBHYA50WbM+_q!^uF8=`t+%}g9*H7cB)#e6%g}{t7@B2be8qQP45}kr{_Y@A$QuZl zJa$^5ukHvSd4}(@L?go`p;w+kOK_9E5*S54dTqyFBS{ejFmGd|H!#48%OKxE5KZ#v zxvl50K%zLQiV%|jMaUunC_HB$_9THBgqi#}iNF$u4HO&6<=I4&hK|An*0>K+ZMqx| zdJ9=$qNDWvl8%Yq8np#6>cM+3D?UtydDJN(L;H!!T_P?%EN6scK`fVF;IiwUfMJOG^i>tf7nbrMm@M`HPV#=lwg|MjLj*<`+dDM(byRH~H+ z0#jHhct-y32%cHGJ>2@Zi7$=Mqm91Da;F(5O3=%D`-ROmF?%)&P`>oOVe}&E-36y0 z9qE$BzG(aUZO7H62Xob2f8*wx<@P%A7VSOQD3+KyT{cgMB)xH}buE%~xVGt`6m2A{ z#AT;fl#;t#nQ0|sSXs@_q8t7BpyI82?{!9Zp?z`YhOv*cPEqH-XAn>e8uTRua*G+| z#ffHYz>O=(m4wDx>Ul{|At!Tg`LadH#H z|6O_0JGvbCg+JE-$t8jfH0vO_#FgN~G!8~-rTayNFR`8dZ5c!^0-L_S(SF%<6MlkP z!a~fhc}>}=tdA+$ykg%AGDvLMm?UxeG!I9kv2kGsr0g_WQVlhNl%071KYp(jJA}U` zvz?;VCy(`Kr}l+IYNf_$tDd1Xhy9;C`a@iAOHh^f6pR7BF03U-x_tsQa(&YEg5u1l~^uKbBeV>nWPq=b7a#qE(T5EEGrkTFu|Z3 zlafl6SNMB=LhZDiA^wjyMLFMnqJlz2?-WpW>R1R85=m($twAE`Me&PFcBK#4R$!wv z-DGFvHtX+4eBne=D8Pn+$wqnCqWw&$zHzsw1^eF63fXK;AG`sK8}C%YxY6z$oJi_c z4JDH9f^Z{x@i;HG}t`jHAb__Y{nlGlnWb%Pg+lJs|SkEjX6+3qGa?ST)YU<<^NY5D~Av4Nyj6}*p) zcw&(z)cgb52TA{`GtjwBVUZ_nuqmqIm||AEThTEAk_J``o1uStd<@x~1U^5C?)ANf zBP)(EZd=!63S8u{ZSROdK9xA(5}C3fq01}iVn|CM176{8DQw#{GFw{}d&pdQBrsGN z#|XX*IZFx*`_AF1@x|}XU4HuNH_6SeRJ4SS*W22SDYR)37#ZLj+D+L?Ys)Q+Pl3Myi77`wqo5E67UFdSz^HmiqjOrYpI zhE#Myrwp{4ywL9-u8P1V5<2i@Fb_{$qd{oGpx0h(9actur{E?o0)o!P!x}YXZsqZG9*BhBTGwGy^!i4W4q5n`mffVG80??2P6zuuof_*(G*k?dt0$4@?H|r0e(aMm5*1V~ZrnTBZS0$1M z{P|rnj4M99)_}f}>#O7+P1Q;!DIb(c%D69s9?B$rL`44WS<58FE@zUSSX|JBv(cl6 ztXLYPc0f^js!)`kN$W-?W7wysJ3S~5uwk$*r`Qe;3P$@R$YCP;MPtojg7oPfjT~>s zZIuKf4$ys+VXYmho5MGKK>k5}3=hZNdhhw=aIEV4`zwOZYf$V=2_bfdk-zNGH zX|VoS;#GskEgkv5rzd%)_p<_D@{%DOF3?tJ`}1unP$ww?aF}57?xSsXX&z8?MnSnV zb2;x4oU5f%ms3e^Q_R3K6wIgg#9yrzo8eI-Hnb$=-h4?f1l6 zkA|n0gJ;mJTk?QYuUWM}846BMXdJML5$9{_+{Vc8CYV7sgpiy*RZpXzYgYPw!7rPT zoSr;4+OZZ(>LVItbBQouNv=KCUPX*!aorrAh|&(-=826TaYqrol^v8`D$U+pM*uQM zj(@~$O+pfYFO@dh@}R#R4GdXnc)QXM75pm0<-&F%u~zL)XrmYD#y$#f?C;KNXdh&x z8c;@gvM3g>+gQm0#`q(ik4(N`_oMVfLRS6|-VN?k(Mwq58(f{fMPq0x)RAo_phE*~ zCe)FZI(VySk1}!(R8BJEy|@Kal3vH)V)TN%TXzKNjJd>WD>!rW&jU!n2Ck+V{trbm zpBAR&h2)RuwnizU6s1lh<)83}-IIvffI!v9d_+Tq592Q&1}jx)t4+W+q}G&h8TP~? zeQ!^d-htPCKaPwgC0vF9UL?N;9~k3HTqthX)0%V4&PMf;dJ9* zs97+-5FE&oS){uf$npsEswxT*ooze~#X4u3GeJ!zpk7rC7Pp~ZRog+Ys^B?}%D$G2 zmiy_yI)nzlK;f;JJ&~(KG_!Gx0!q<368!waj@5xoQuVb=Ql@W-?U6i&80tTNJEp%F z@uvu@zMi^!6HzAV@<2)n!kxiDdJ_tFUL8pF*A1kON1%b!fh}ranni=-Q+Xa=e^Jxf zMJ=et=Kmsnt;PnNdd<5eS&0XI@IXHd1fAy(g2#N!-K;vPjvc_N7rbn4hOK(KuvKr$ zGk7?bX6PTKO~9&`3aomgZPlN)>@HF3ymNG}%@2+z)oex?W!;!_kLzes16?MXG$&WO zOxS`h6Cn!mZ0_n%PFK=Ax>?+)eQc|>y)C~$^W=pg)mSKyg*Wf9rEbBOJy0M^Vj_Qo zAr#1R;@kM@Xc;j8dG+K|xnQqeY`F)8I6q;qq&>9a)w2hjwQTx}D2>cuf>$q_QEX^M zlmzCfDcImuL>KTcAiB-#XhB4x@{B- zpsNzxWnwqzGVyycp{vsKtGVpBFnizJf_{uE=rYkusiEh>1_hI*_?KNSuC<*9UcI7a zuO5fP4JeSscsY=YdqItz`%2zik@3uE9#C{9&DmA9@ewBOLS~~iRRlsU&gg65YtY>p zn#nQh=|$Nc><^`RTXrWlQt;D&8NsW^FfawYdM_Maz>%aLH;nPui@V1#Ck9H-@1Oi2 zeggLDLCuncC8pmn&o3#TX>FQ$z1m|U2lPt%N0wm2Sonr+e@{lQGP>Zb&Yxz|gZ|2! z>?d1H!tAkSz^gX}dG(@!SI;);^I)RZv&t)Dl_QA@qxd8tJEozc2OhW2(0e+7xm7eh z)T6O0qUYyH3h)#YfD-awMbv!6^?r~A54D;N?PcQNU+6u#THDlLM1Yg)vrpU-RRIE7 zzCnR3uZWvjgEuCDP*Qj&t8-eYcyR)qvJTKq{=Wg;PJkSxMF)71-ZW^6e2h_gqbC;w zT1nVViUo~%j!m%wf6;pi$Jkpi!0$T1BdxIZR3`LTCcM+Umkge8S%-9BRK!INd(4qQ zB?91*Mye-az{U9Hj(2t8Yv{-b=pVXe2*`>Av`LDG#{Cm0M^o%bB=4hjfcHF%L0*(v zN(h0OsndHRy6XlW)AxpuJ5YCCLLMKCfWb4H4B`SUrnsO=)5@=RCycCx_pgT^`rfGS z_3(oii*X{^!Oj|IK@8~aNU|A1>^b3Ik={V~$dJ7qqkB;1%mR-{dpp)V#nIzlsvyx_ z%sI((@5YLMCuRPkJdUDBQ$>A5-9wJBuHiZ<80h6tvYPJ`5FnL@)~Ew<=fnuB_+^Jz znn<>G>_x4^f*zooVj!|Z zDY!h{FQ>@dm>Yp%uMTP01FuDShfl2j7UBLE(1Cf+$CDWLz^uxgbw*u`32E3nu`{-Q z;i)KM_CxFB>ZDu*5S%bW9Cb<-4|4VJhUWCE=!)ZF9Z!+dHjzj$tmq#@`c($EMk%m} z9VH1CRb(|kJ+q&kMBlkJs)9u<`^a8b3cS@3PvnZ5s*fTWJJ%hW@<-bsNMcdSemvX~ zO6Y-AIhbMFG{Dt_%4}$WgIGkkR)bhPno_2N7oVK&&X#N%JC{pV-))cPJg|fHiYe{}D}HZC-N=*3I51`u?!NdAMv# z^u#x3mFO+NT1)>H8OBSPmaKArOpS>%k?aahxNlpwd56qw+&J|LBnX@_>R#jie!?oH zJwH=5_|>mGmx~6CFAMYY4uE5!X(SRcW;bM{?17iIIM?G9)<(NGVX zPFRhM!m*;6cXA3>V?{ypDG_i*5dZh~xl)0Hl<38P zcpN0-bO7F{OuBL5+$n)1B>I4m<7u=67YPB#YRd=o9lxPpV0aZO&I)wkR{sF#;US>^ zNZtVBore{>$w00*rQ|S$xc>>{M?!nZu?L^E4qbs;3)w1xfP%JNBM0Rs?~$78jssXS z?r;O4frTL=TJRN_{VMK}*p6rp0;8Q?FBBOtSm1LJG4L(JJ|!e}CBVLHC!`k;d~elQ z7h7_G_UJcckqdmA)mW)`(u4Kw13Tz0lR$tw2<^eUmeSNie*N%y6zsZ>ygr22vJqc& zX!r(r-Sb(Q1W__Al?36X-8y>>cm|*>t3#8m*+K-%b9mFExwHn&G)0q?6j;=1eWPnd z)OsjgU)QRv_m@g!r=TR3hfvdrD!A#yWF~jfpk0uK!eX&{vm?;7T3X_NhBx&#W;fmu zep$2!O|qIp;cI$9+~znOxB2*XEc<=um3(H=3$tg0Y2O-}Y`FFW)X8WwCC9|~G!((MhIO9lkLGieKXl&U+HagxKbU4e zGZXDMKhBc-I%uG4Ao+$+5?s58(fr(5Q>8NT zDu7X@EcYITVA5<`ocKFaY_-$rjQ|T0fD@s<3B8d6G*?|uu*tM?xEG~Z$pNs_p)MQ- zRyp~$Zvp`3$yv$;geMSl@<8ws5Q0Rc9RZF_1|s1NJpK0s^<>1X6+p{C+|m6{Z|!is zApdRKwc02wEvo#<>5W|xmulu+PzJFC<_;=DL!|2Jhlwj4HD{R_2{B(sd<5dKn>9(E z;;iN@=>0R)77{5qvKM}iJv zgo)CuE4=L;LW1vT90b(>3=<(?7vbyWXj(@GTG2csCG}va`;6Qb#{#l&6$V0Q1Cyc0 zB9Y;p@E57Lh1_n3Q6xkZd|=3sO}1I-&`Sy-$dJuV05N*aI|!ScP*RPEA)@eNC|S)J z1TL>bXaB>bP1nA z+ENfua*;Uw1t&RVSj456cA9Y#_a2z$2>Q*x=pMbM8Bpu2j$BPSDgP>Y2N<~;EKdKz zI>hI}B6izZhjR1U1SST6!(Soqc07Yp;$)lNPqnsW!c8OQnmwA*%ZHL}y@NwJ_3Prp zn>$WbE?8upk$joinIYnq-(WwUdXEeA!?Ns`*a12U?g0IblLx;*{f!TT{>J=MpuchU zBMqwiz-|LYfggmU!0(68nKVN^BXFJ}g(BC~=1eS6+>4o^3Au6Gk)>Q$=9);#C>qr8 z@vTmeE3O&Knd`n^P1$t0yKLQ)JqTI%Xtp)GLDs#D(6yA!-wBPdfOW6s&J`xux<|LP zn7rIkP#80C6i(SZ0i|pT3_tbaPm598;M;AI4$@eRCR0Hg3xmykA(>eTv9Qy_>6;4% zMGJ(TYs4J{@VKdD!hx_;1$q?3fSwTtEMt^Y6IMG4ii40%c0$OeeY1_4?L(Ja6^0;L z;QG5>bI+x)y?nH_Z}tFX=VCe>8fQa4^?NWEFsMjyf;g6vs4Y{2Tyqi))xJ>5=D^t7 zti1}TTEUqYP&&BBVO+-!6Y6k9Dwq7c;6p~%%$6s%18L_8tI^tQ_Je$3K2RP@eSPo% zpAYC7;aZs6u@bWxxo;W@2v>Pun#DJECBq=4BXUc_1Akr{D=(wR94p#RZLyGvZ=AQM zG=`QF!iS1HiEJvfckxWiqyO47$<^T-pqo>KNs2QyG@CG^xEXe*4}3Wm(TOv#`C()ghvT%lNcbt-74u#UR(MB#%_cx7`z zbR)Gb=n#J_36?>u#%$8OByOfav3W=wq!k-96UA(XPOmmokY8@5pf)~XgFqbjA0Y{Hrye;z}Ofx-)SDW4>}6EcfcJ5O|VvOtDRXv@126fYf?F=*58aHfOC@d*k1U9N$SF^mQG;5z1|HtM#44y;D8=IT%fRy9KlVahB*AuQ?#1uV9s(H9JEa6SK9+Ty&qA zsZ!Y25%)80MG1@TUPa0VXGh+SOYY)cV*Z(N-7aN9p)VtuGs8kf&XB9^Q{HRi*~7L6 zofZf2Ep5f_pq+v;Xs6&3yPU^z2x_O`585fnUm)bMfOZO+OjGl51BbQ3RY5xiIjQfb zgyfi1GZTYz?|4Wg40S*);_V16;`Mgnpss>;DGO7=Z5#u(z4_PC@9-^RcBP(EkeRP# z%6c&^5}vQOM!H3NEC+3xJ905Vj{-2?o#EkSpJ=)^Y{R3=qO!eqmtJ&1f`ih@o0B*5 zQH>IMw0CHKrkDAdEC+3dtLkVolzed6t}JbVSCLT=Ia$%Q>l2EueaSy|w6%h9aJ8Xe zt>4n-ueI2)rEO>PZRVfAHa_}j$i~M!oigkPYhFNDAJ9!! z+}Z@4+>-SfR&y?NkQeOKTYK`o+5+C_0rFVjodEh`8MmAswUNMW3>^Rxd_i!LW#&WWp%oOg%06IhYNFRs9e~r@9o6$HV zoMSzqv`eW^*yL3NNfW&$BrUoUyEZ%FfD$$l+9IX0On7>7 zCKnbLJ$n_DVfVju-HJ@|ub}IgBWM3RKsp$o{2S;x$}?Yq{PS;xbTD`2!bT3P@2F4(T8vt>}SMWJIitp)TsIk5oYhjr3?=uBBx{T2x?t zmuPy&q+v?-gK(Ulere#De$-S(nQ4Bgk^JR5Mgm5aB_jdVf3@NPGkSqR5l6Bb3@;X1 zN;*+<_q3Ce;=X?OcM0)yDpyk3>XC!Zmd-K}g{GkQ4i2pJuyl1ul z%zv&jhTm^b7)668It&kym9-xndcH=mUj~dj-B$C_+d%Ky*L#Z2X}Mu)l__vFH^8pu zg^sT5K1ZQqJRfK<^WH|7V5^g3b^d3zIwr_g7rJVz`v`1xH&w0^Y;_yP3AVbaRa;#R zu+{w|=8%bDv+wqUil?ED33;t|(xX_-f5zRdhRR-^Pmltd?{J8o{r3eBi^|<{YOisp5usP=fZcq?N=h2AYGjK|!b)a&&G?C`jPs!~ zJ2ylg@$r##EMQ)oye6D?{?a6FQn9wT>rdgN_JjBLdb%$ZFnJc%Jp3Ww>&D!3IcP$> zs1_gm-clLsYuKKW%=VVge^{rjfq$VQ&s}24Vs^+F_hn0l9b4gS+<8s4(}$)(b36~I zL8$B>*&kR=5Srs1y*`oPWxaT1az~<~!58*DTaG;lJiKLBY;%3N)+re#wW-ni-!P2% zp8B%gvg{p{CaEI_zmTB0K{2~Z2+dh8qq&z-ppw#>_tJmTj)Ra+B}sQ;_g(Fi!anZ+ z-B0C#38%xW9KR~eC>MymdEVToq4&=?R@I#WBHxGI)4Wb@4tzGvnG$sfY7rk$*^M&) z?(ZTopyOEM9XcQ24fRey`;17-PcL;YeHRH6YkYrmIbt)8bIC0t4kNO(-vsoC-+;Z5 z^iG3oM?j4on=aHNzI(?1MS0B<+7mtf)OOZ)tVKF^B^gr#s zb)8i=9laF8D7V_BMUt*>cu5^7vulyPLck6s2DKHXb?&Jm@ zMHkhz>OEAd{4MesIG)owWNLt69(R!iIC!+KrY0$h!9#GgExA(LMskV?3X&QktdnmQ zi-vCnGDS5razj2!^A)mK3tt{b({&>Lqd-1?=x$|Gxg_NgIISJNBWA;$5RUtrK0|;Ch6%Od^ae6to#9RpY17t2p`dtUhGroM8)+LZ8?Ql7O=ln`coBr8V}l2 z6-l6hYW+>n{QWX3Ve(C+n*%>*N|xbMB(o1n^GF&Nz~t%dBQ7*UcamId_DwWWG6`;k z(`e)GgCXv3Xlp?i++Wq<8W+m6P zV5KTE1bI_6ZJtwqJMC82oaq8Jfhuh(o7XW6S~$hOJe>)L+UbqOr}Zn?z1OE@ zU{K@q0}bL2{g4nVzu#~zjl^=_%4>x$5X&#!p|En;SEhkpqWe~^G5GRM*b4lzqWh3` z*`u z#AZa>>|S)TVUt9p9X^9q1uUqT8s>jirWR))BiQ`jq_*&zRq^ti!q-ABpbz8__9 zk9x8Wh;O!j%UfYDyr+w*tsd&22eZNxRl03QC>YUCqI5IFPoZS+h}~eVh?M$(lmqye z*pyQG(fOD3^;S+)=)8o+;TYk|D9O>I@uy(&ZC5Q~xL*&#abKc@b*>Ek%AxWH9e>Z)6Xjo-#wgT?cQ)nMQo94S`G|O&0{$ikk zUQeE<%yUK%g~i8c$72r_>KW+5xUi55s$DqHb!fGgR40Fv{o2(bfV{hNmq*LdxxmzB{TCO>G*BB(jm;91U1*~S(?0b zfi7JW(l6s1^|eC?oLac%@e}<9xuGA5+z&BEF4d(I#SmRbcar9bM|FZfg{B`$FPiv6Wpv0Obs8^mEw`sD z6(agrsspQnKxiigo)3i#KVU?|OS&+5MH3E#TKM$yf=jCBI4P>1M!4>H0>FPu@s%Y$ zU5fMNi;sj$J4T^49OeuUsuMJnkPXJ@$u1@S&d4Nw(BtXK{)6q5{$F zm+2Uv1`c|Ug86|nS(!htB(kl$cog3LSur^j!k-s%|-xalrT&T&0Y|^6VcCyDJ{SV8? zVLv68!RK526lD8G5sGWT$-AQRk2?_;2`tzrgpu9@pq>#X+(3N*ti_-0Tb5%$Q-vic zNd$&Gk?6Y`K)p}pGT6Xbv|^?q`UI}alVggndFSt-29Gd8##&QCOJxsGXz@hcL$K#| zQG|;>Q~CrMi}yl|n{vNXNyk-`u#3gT>~Tf;j=uJs2kr*qL7*HOc8AzEmx2kcQ6X)IVZ6jQ*Ao~t40P)SB8ut56%T$$ngl#nz<1f zAvED>&|Q$aq#QBA+JcpN45Lxgl62&0&3jmbH(z6v`FvG7VoRnS*&Pgt@FH=T?|-DY z2m^->q{CZT5B?K??cO-+{{mzS`I^2H*y?-esqPd{!nDm?Yt!5Gah0Xg8hwdY9(n}9 zp=NoCk?+g;u{fnA$*Y%3 zM}XP>f#w(IH15x&kJ{HWZ*DXxwL(Iq~#+wBTrVbp@lqfjdUJhvwm+lZCo_)p?@A?z*{8*!nP{xA-?SUj6x=3S+hf%ks|hJ8ZUaRaf7^;CYv;c3ADXP(c^i zLD}<4wmCvcV%8C@f{olDDZ)8@XH^DAdP~RqC>@VA7P7kA$ML)${lwtOGfulA^Lb0v zQmotbUAaQd2eInA`z&;Q4WTtg(zA(}4D$lxu^s(JI2{lEyJ@xMmUitlZYo_e0|3 zu<}okhPx`~H3C9!RRn2G`;H<-?qH)Ro|b`r9qHzKH=qzGgm&TwW$=f*L$`9w-H!OQ z9H0zYs2MO4l4MAX8-E)#Gr{Ksao7a`Xt0qLxsf9-90KM41^64_s9!LPq2wt8Y=kEj z6p)xR-z9BwBu03G7A9>`)&*$;F#dkt3h=ky!rXV`Z>!UPsWQ)PGCzlUHp&I}$|5tO zmXX*}@*Nz1xAadch9NbzignC)3&KbPnO$IyeqO{8YLX*Kyi>3$@Q^%ipfeO6Kb&D+ zeFnj&Eu_}^jgoKWUjx5EjxK=q`zS@_Q3U06Kw?JGY=aTLO72LK3DY>&Fz7wV>l`)&i~~hf!#%{tt&P-(nm$AsWZAhh?fz0exfaWk9y| zx8e6q#k<1(T6dmEvGB?~y6t#bc@Uyw18SZp2*8yYEFaga9qm2Pr5d8OF8=k2_itIA zWly>55r>#qp=f!WK=ys>W?S|GvFV}LBEj{>S>|a84}MJl2Wus^SLPrk=e6l0f2Jin zI;hNGEP*RC$c45fhE%Yu3zKyfkUa@x+G0Xxn7U_c!Ji-;=lMZfX($|LT<8u_U)#2#uMO6$O8Y@ksJrDQz!qK-xRVKNw-5!kmnu&6Ba+0vY`jBiG+)Ljo8Yv(N;n;?IOpO}w56wT zz}}yvBsmUxt@D(g8+qa2?D=50Y$PI~uJR`4auIk+GDlR4fzZ>l#L&}Q%(=W#pwC`V zbL^=fSLs{^ zM$`kDt!STV#qcLlOHgRvJd{62*J4iiVsf+0x3eTYW+J9i>m^is*tt}Ds5_IYs*~V6 z>)Sce<)Th#zdSu3UTEgP?Atf)z-+N7suKl5AsB6oh>XBJPUXGt3NAZvC_z()J?s)( zPj4}Dg+p;U&m)D)hmU2Q+RnNDEr`oGrCIvu*4dMDfz21-xSY2jE=L%|$(IqTuLoP8v5IX9rVoOMfaIq!*aId}dT zP^+@nJ!m;gEI>RuXX2LUJnWy?Yw4u| zGJgr`=~B!{*bU>LUjey$_7OTN;JgQoN}MwEzsS~*!0#P<62)o4avb_pfdfg{Zpgh=fWMEsq%m=TTmBNPe3}~A77g9FCB6CurK`+WNzM849lJc?gV%E~?-^|~F<1584$M1Pcg*9zq z-r`qq%wH`cE&*-fZGX>ER7ds4k=}hW|gR+C+5T4*KPXX}|Zirh> zkAS+uz{01r(wvlcsBRwucoF~! z3)=zJy1#7OvnL3!_Y0KZ+n2<(k#sX4bvLuJ99ct!*r>>=^jh|W_VYNt8>B*c02Y1n zs7c>R^#pvXQTP25B=qeD32BM=^wQZ4w@4%raQe65L-w_#q%3q9 zoOg#)v8JnoDdY~&<)Hj8#IUwCjr0f+0i01lH$(BgMupY_vVKs;@F+Th>d;prs1{2) z+NYj9yb9!s61C3M^{M+lL^3|#ehOc7T(X>%<3U-4%8&dn{YMizo*k}motahUzvTBm zmp}2LYSt7>Sz!ApyXh@AaofQJ=^pmuE><|>6wc~Oqx0pGv_TcG>|%H`+vBCoT-*2( z+b$eBXFgcOI&dJFAWNXN(=GF^swl6YY3xbyGf&|*(akGUACAt%C2m&24D*iI44Ecx zv>t!tRiY)@`|7`JC+?!hy7LYxb8u>SEF3nH5m0^jn14l73|Xp{ShxgAupHuOuGg> zPT%>MF!QkFfJkhpyp?d-0Bh{>3k%^gYOuT2DX_p)&@ML=n<2gUpb}wlCWu5IMzO#* z6>B29!)o67c9mUX4pWrKl+9OaWlWCYH`V0QWKOPOV2Sp{ni>pK`YgY0;;Gm84S)cmVtV^wQ&j<#Od{kGR2+2ZvqFI`K4psK4) zA8hw*9h&U3Qi{g~PJ|1;8nscE_|ozGMO(6Z>U?E^N^zZ8s4l&nc5=7h2L`8hb9_a$ z1g^U?WO~7eWRXt4o*oE)cImrt%B%xgI{T@wG)=VQjV5enYr?N$ zB0?I}4s}+K61p()`5T;m3J4o^(;X-r%g|59T_BPlqV^5n3J*4f_QR9!fF zprF?IF6`rRcl<=Ct-k!k-K^}ykbLn{w|7r_UPn-IN)-Bpc-saDH0o9s{>CIY9C-qVTzu}v)5qvZjgs$*$O`5X5KO3ki4VAb+pANnAc!7b{~FFvixF4 zf?~~w?l1!nQBvM_2@V)J3lsQab}aoD35}r~`4Qxn?aE)JL!tHYO~vtn?&b%mP`JIy z&cc|$S|m6GKL)@$@101?JpOh$_}p|ZlxUdd_B{pm>KT;ppGvA2kke;Y#MCeu4BCzX zHYNw1;ET;4M*VbnAHd()9nJW{TaALQA!VQ^;=b76Up=Dm`v`mYqg2CNH~|~Y_cUw| zbm-u(2AzQ0jCX>c?K6OM{=>gd!4p2p%WtKTf`4D^8plYII~63s279OuRfPq}Z}81B z1WoNv&0FRQUYkyPI{B(OKG`-#6{peb=+`EgTQQ}cvN=cNnhG#B*oNoMJExY{zOQ6e zS9WcH{~KT9qLrt!*Z^J(XKV@yj$DorWUaQsYT>k0%Wy+Z7mTEuO*V&YBM-`o_JLB zT*|H8(K@OeDIj6~NX0xpkWFw>&+oHeqjSt0Rc>ncsXl#uW0xT-wR3*1fjHidZtkh` ztt~2^@uFXX>~d@~RqxnYwUimL$A*P2zsNIUXDKnnPAjcPBwfNrob~j81Fh~yUj#GT zJ|J_b)@od#k zMTptOX-VlmKhWdpgIowRLu=zcDqDIcIeAVYQZqfw$SAqz+><{r7ISbYCokhug$ORc zrbWIdH`dflIk}0Y=+?2yD1N2cmlaf(TrnXYBFX2hwR#OA1zKhN7{_ItG~+}CaXc*_ zCIYx*4ROiX#<1qVY~i<+8lAVNb(u3r?> zyWJItg*PlIhm}4l*#Op38i^-W~-# z`VblMelq0H-~~|0#*1p?$N|KqBGD0yC!8NlE?@2W+(s_f?Tk&d<5iLav%^`ZD*=TS znCPCupg~_fY8lpNF438ocFgXm3`0P~pP&D4$f33}fFg3xctVMwNsiXtsxeDr{fpZppI^d(D8rvNND*C()m-9Mb3K#Ky4^6VJ+ z5Aq$r?jZwjl#wAhl?i@zy1zIF3M~4b2a(DENt&KPwKqe55Mx(d{u*)bfx&b0Z>ao2 z7+!g{Tjm}e^lirFOD5j;*39o_rm3^b{^9LOs}J%tqPMI_ zZh2Ze%~~p= z-ALErFV$;rkUu3jt4gnsWx0@^R^K4Yv&$T$w6YP4Zu2o?W4|HuCztTK<7d(X3>Ak1 zJZpdI%EyhU)m79<0B9pwO0XBebIznpbKM!;Ayu;>A}BOcd~soxasJY6b@yoa{T`=@yrQ2Ld@hQ*NuHS+o~mxG zs0;@TrM*US1Y1z(X3Sv!1Pl&~dUUCnECf4E!(>GwO(&kW2Uv$yn7p^2sstQm^t-~) zf)d8;I_4Bz&KCSg|)vEk{XLY3Xeuq+{9yzv5H9W$Z<3qZrY;3rlU9xzrhvl(GxFNEkx z&T!v^Bjt^)>2G=1wY{XMZuXvcv&g`yd(l*~oKmy8`l7<*a6|>~;PX@kkN0)!;tyyN z_z%Q}A55Is`@!q+C$|`L=RYRc^LN~@QVZxv<-%k%6mI=Ib-8+RlTe}S%$=Q@ql1B) z(nF229v=DPr3>PK%((jIo1Bv7Zv4@6v@h3C_WeRHZc&||WyaU1q+)t>?pIOyX<>!2 z9LHajZFn$-^^>cp3+R4(3gv*rduH);T>m9})%CNy+ef-HuywT3B0_608F17%3>-Ul zP0r&TRv{d`3}1)eS<3k9X{`OJHHA5dweR-ZyMHyr+TU?;jNDmz1wcqq=)FrX=1%DB zW|HqPQZ0=}>v*GR0>Cn#PRS9Sf~OoQMGrxuN0iq2;hRuQ9*lh|3O-BaXUw!Lt*Kg< z)>I?15w*s#Q{$JjaUv?WRo?rQWmW!SurE6?|B!O{?4y>cEEyfW5w9a^p4sX{A)h)@ z4aYm)SKMf?J95o&KD$lXIJxNKwH;hnzVz_DvC4w(Cqve@)zlG7bE3hFpE?c(48NRf z8~3^Rrw5e|{LgQVtYLF*!eOG`0EwR32w7bb>st5=8>*q)szj7KiSnevaF2zIErs?D zy6@_yqB;Q2Zf}>-`U-3>IiUmLYS6%p=1U>8-Eu%<8!1=-d2tXLeTKFvLRh)96uk}y zV4G#55fWDuA!-RlhPOC71m&uAEnA3b>DyoY1t*-3dbi;Tdu zwoKJbfrQ2(-$>_1|MySpaTPJY^>|s*+9y0^^0K1EHOu?8o$-zZ=PFOkv6TsD0Jl+l zu-U=leE5`IsBq65^A2EXC%`_Jsio7lCoh(>EsSS~S~mzgnnm&?bXDQD#retIfolEA zV7s83MaQfN3d(}>Xf5~+B;yG9v zX9=#^lmdhWPGKhL}AW*R%JSs?A((4dbluE!mV_eyE|g`f*4#ev6+Gzt?|y& z{>k16lQUN?LKLonF^fG|R`Ob;UysEZ`Bb!V*Bgk)SnU@#vY-vLToY*E)4IUC{Vy) zguO#qBGEd9?SO?lGBy3JxXSfb9dxlL;M>0QV&@#_Ek|7JB@4uhoo|_OUA;z_`aS}5 zGJSeIDobB_Q#ozIjxd@3Aebhyw9l&(co4KJ%)i1Qwg|-Kla6fSU>HmhHhZERxKxsp z(f<}OJqdy7zU!{vIzR#8-QC6wS}Nfof3?u~WexTpE;QaREi@3cD+H(USJ*LNFwl6K z+;a`@)?ojLILUm)r;gA)QSQ9?GLfn%YC>arp}(c)!fSlYOAnET8lMB%9xbNqGUiWT z*Fik0)Z^v(V$7+)jM2B5{_P1B>6vRVab?t2EkJ6-1Vk#+V zPk<{=?kZu_*)#wiVF#oW8rk&~Y!e!jTN)>*adxvKN-{|(RIOw=DlV9qs!2-9LV2ec_$NB>M#8eCW-U2_V z&bMYKF=H#Bnv=S~n$XgzJd~5tF!)LrxNem_OfxHXiHpmgyv$)$@ToYP5G$_J88O*n zF104I&HG@uc<`A1^u#pN(mG4|WL&>8zKR12deVwd=p4;hAGue#s2%%at~Aa5;_sbX zz5009mxZ@4V4Sj>k1Cjckx!hg>-Gb2)?GCVzvq?*=)asxe9|@28btuN^(dit6y(_f_2zL`lR6!Q6m zOiHK{%#(uxW)pfM%PZU*D(R+UdMvz(K(_9S=-^NTtH))&mEG?B7xD5J8DV+?=tj4! z2Wzhhi@O>sjM`2mWn(n)f8M#*7oBkb^Bwc*Be|hAhiK^6K0ZC4U(;ASaBx$M+fMDW zhs8X=bIVg0S5zQQe^~)|ZcTfdfamsEQkDB{Uf{V6SbXsfjBB(e3FC^0`zI+*ddWxD{w>Tics!@~Tb=^x0pc8LEH2D3_(DHjHE>g4uYz(D>;mWvL^ zO7aLN07mm93{XP_Xu7})8%U{87+Z_)R6?RxB7;o53#9=jvb_67 zkg@IX)&W4ZgDKF;7?8-N+MMBq7`f%q*k0nk5Pm{wAD^R0=QYOV|~m zl??2+SZfV`t9P$^te$HRc$wKJD2A{IzU9nPmcxe3@X0vJm=s)CxYe#^6+Mx51Xp02 zoyaC5QPHx)!ir%w&TJ&1NSS#~PNZE}ldI?_UhYq?k^j_kfARy|d2AH>`pH|w(e34x z(XIRZZkBssbi4ko92nhh6uq}Jy8TfWuvJ=nRz|n`h@;!9h|z5{+35CHcy!Aga3xza zU1v7LCGlQt>+wZBbxO~YUr9UhfY2SL{T)9`9VQK}B_5vzaFZcDY#6Cc;Jm);fzT}) zuLVRSS)5ed7gH-KG=)5W_nOs_NCYViv%|NZKxpxxSMCYYzec2F(Q;%MS;{p0O1hwi zzQWm#{VIrYOu{~8XFg1!0@ro~DGag0I(zFQK%i7Da#GW?f&U&Q-z~T>g7fT)@eV8J z=@N}x)19xE)xJw-6Ikiw1|3MItCBZM=E5a39BIOK7l4wtYAf4!4N{38o5fNl+D7`E zR07|avz0~R#d5yo{JZV(4_7+NBNY@a9BPMu7UsM?;#`NqK2+8KWEN3&K8}$fyO9kl zki|)XRi&v_Zx@;twvl2If$pxs$T%qoj2;szL$b?&?`6ksJBy(E8rB={`95ZN2f%=o zh~fGd>mX5?oDxWrGWrl?Z|oF}3oEx*Xl{wqNR_xlW%L+WFQzPmXn&u>3((qYg!I0A zTS*kaeZ)>>Dq_rym#0I4&UsABErwHjEXDUYqT>NGJ<~yX?$Un<6UC#WZSE zIcYTYLhCl&0RwJ(lSUJ_bPJVn8^%5fE{gg$lo%PTG9$a!G%_H3rvQrjuqq576S~1h zc~+M66r{lT2W1-&CdG_Ey>S2vi{iOZW>)A!_m7c8R?(dJkpsfV$E-A-tXNsufv@#e z1i+%R2X7%RYKS=eMFFKy2A3J&iv37|2b3lUbH!*ktFrS>A$8Jg6pE9Jsw<^F*=S9! ziKM#)zAelBvi%5SHS{I+E0ootuXP|swxb|M{#nvH2XN{0hbd`h-FYZ({c(t9KPiZZ z87sOON<0=_nrrUSyxo~j?smL#8Z4n}4+LAWy1i@JXVFYH_-gR$q2& z^>hNacl%ktZ3jq_8|$t`63U#3sNhOHP$l0x^ECYW%#n zE1#WM=b;Dzg)Ekl_+$34tQ3TEL$Xqr^U3T1;gku)3+}UaL02M&39=txVd=A+UInOb z=`O4+#V#pJ&mW(g%xWIUG_;C+W6tnKZ3XI3uRxt65Y(}Rp^hNLA9AiEgF5a+s56*w z&=P@kUa#Gl&8Q^ma-_3jv~O&sZfS2E5R60SVklT|WhVin`PbNcy4m|558o@{07sf+ zm_QASyOmHmUPLM!H89}+s;pa7ZovKWs&sov!%YjlzxocPO9)Um+=%%ld}zbHFQTf` z-=;#E4ZD)0!Pf~q@INKCIzC*VLd7TLv}a@VUOOHunKY@=eJN0!-YQ|iD>xfq7?|xE z+c1MoY!HDvHCg4NL#!Q-#aIZ4+l};x;&!Ke zd5w~pm4Wgv&=VxQiw!2|LE_zxiVqYRN<#0!a7> zj)EIirou=6@u~QLNQYg%)9tiZ=Nd zF6vSJYgW)oxb}dhail}Mr;+0z>!WgaqGaKK*jm)O2n?6Q&i7K|_tvMsfhQ?m2eWW# zxbrw2w~bRK&K&ZsJ-_hrmU)OA{=`x4(Q<~?$XtNVc6HrrYuvusB{Qbf#=LQcEpIwM zeaw54_wyb3FT-P3IGRqI501({#K}pc;P2sd;)R@nIT~dLil7)WrJ*5m@i~)RhfyQc zD$V&M1;`DyrD)7?C+6c3omrxW~-y)f6>8C$F zT-P}l7^i}(!Bwj~=%mN@o&IwM%mkEsvihFht}x$37?Rw5_-*up_))z>{B{R>7MFC` z0^%JXKKlOF6kGU=lqNc!opL+BCZbkWD^o6QBufC04fEah(x}fUNvG9X>vms3jh7HdB z62i>9ow*a+#*d%1VP=3CcfRcYyE+^Y3m#3g1k?fW0N^tW%mpY=>d<6h9pFvEYJN{0 zUCMu1J`2~?GcK`9uqSOr!Qi8zEzk%r# z83Z1_hlCSX>ALJb+pH>BMos1LQb>Lm`eE zOdpuuQIIExgJ}!`g~BR;*nGX*qyBf|I-ayw_%%`+#%4AKXfzlH56M_{4)e4cW()Tl zN2-huGdE#Ir@(zq?usDx>Uo07QSodI{-6N%zQ5AsuBYwe>fwFwazId+mrH3#Gbq>C z?{j*R%Q&0i3*VN;6ydWyuL?8jlGAZV$Y4L10#yFQ3keFoN@k}sQ`#rw+08&Az|KG; zNus_5#DMd0p?LJV`eS<81~e$2WQVN3B=YMe9X9^f?l(Z`d;#VCg$_5{*d+PkX2)U^ z(2g$gM|r0ckU4E9AsW~XK}EO$RQ)JV@G`2r6pYA#`IjDL z{sl+;GM;Yp#sjkUcF49W%d$P%VFgkWU+BPkYk{W})bygcmr>!(FjZ~( zM-DPrk4S5ezHHy+lRMJ!WTYKst@>{eVgGH*Zn)xnzaqZsT7Sv-or7VD)fxY0%P!wR zk%FT`xWeYF1cw~&iNwnktt=#r3}D}s0Q>fqu3IwBFt>7_vY4BqNmi#gCI!VKW4Xty z(`OQTW}C&_M0s(7k)nqTMVc22YTY`Ga)ocZynZ(Hdc>4Tys*pz6th~{bWBLZbl#tD z@7c6@eqe3L1+@%Fn%#Fe6pE9af1STfBGdGX@IK*j|RQT9!tB85y;>Dg^oQ~>fVxT7{@8So3iMF7?!b6*(0fP_0;cdwk z@eWII9f|*C)2_npdz;zDHUf1lAZ~fLuff11EkqRpva0_ozAA1ksDwl+y|H_~r)NEc z6c-j%BBP?gd3;m1or(lYKo;F5-zxB-vk?8Y0+W_r0LItmI3`woA6aS>AWyBZ#ofv!pew4vetb;vwsA};*Tn|5I&`oE)n zCQ`~RjF}=QcU2An1Lv;A*>5#)E=!;Pd74vH$q)RWpy}r+fbj$Lh) z;KCSg~@P5vTWk+${KmfZ=6)@tTk1=>+Qqj$p>_ z^+31nRUHAiRN$$W^!Ql5JNa6Z`M>?DF5*Eqxk`MbfYk zUwcI86&YVko)iV7$JyQa;$B@V!8NNgN`M1O{IIg}$kv>wb+$>s1?o3l>u;;Aqw%FD ztfk|cSuDO?iKyGxlYDGY^Elq6t>-7c!o14YVU5p(c&yVELq=H3yuUn!OeP^3J4QYc z%IRa$TN-7Cs!S`im=MV%D{!g`>T@~$*CtEs)HC060-w>+HFQ{>4Uwv7u zlNBdM~0?9`<9E2MF1)nK|0k~RHAttqSH!BCV}{)?Ge;-$XL{-12veHxU}i<$+> z=47WKW`Qr3W`R(m)9Qr*Un?cq4gfUGZ@qfE0HvIVNM(mMI`2!6&=c zw!s?^Vtz;t7h>MA&cC9=hap2OdCo8}(4Ou_{w*T0H>KX-fl4Tf#frio{m4%Sq1#x3 ztp5tENW`Jx+AmN^!$e?-Zu)^Cq@I1-=tfT?ia{KI7cJg>a{V7lzh;TjuanE6SS#sR z9X5W`kY8E+D+j&$yKS;^B{ouGb(}==Q{(ex|L;j!wYuH|BdWPtyW^ctzJDE-lkMZJ zx8#0`I1e#uE!j3TnTIU~LhQh`einZRXmZ7y^dbt*!5HNMIHWW$Lu z^d|tCW70GWwEXnZ8IMf0vRA7ZyG66y*RHm&h^?#}Iql@v13P)0C35?G`(mcphBqiv zmK@XWD{SxS&+BuOg%!t)duHl32*jjZ%gT)st-f*`L9PY2#lHyg82=&QqO zL1%75Q3AXlZWMQ#w zSU-<&@b+FRZGZG}087xZlW^-?E%~|Ub71TkvE*m)aB@1e-Zhnbk4ha^Hl$&X&Oo05@`{EkD5@)@~}oE%wbIvTXU(v??RHwFk* zvUl{Rm`}~@U6jNI(z-Fk&CLm$3pA>@-1=Bt8>ol*8+%Y$caewC`XFk^r0_O3I=G4W9&FVdmnw9;<&SN zz{59pM$`?0viYMFC7)pGI~mOmnbFj48uzRT*rPs-*Ld59_Yxi+Qrb6_0TPB)UC))p z8p7|2RHm4iU$TB`BGe#9Xp%ODaB+G0zX|Xmx|NVs9$*RG(AJkmxPJRQ8J7!Ib~O=MIh7s|2*J{6BvXQ{^>qh608Un zfsg9Te6v0A8zse8ufsx$zauIBx8^$q6jKTnR`?Z*-5|}f-9_=UWDWJo3$Q!@pioY| zjdaEWE98UonqtW(AO8i0R3Q1i@5?r}DR-obk0}dc7IWT7d@r+@^}S>RIxBKH(u*7_ zTC|jTjyHGDZzuO708Z2sJAIVQ6~6H6aYUr+_FK?OlcFQF{>3&Z`Dp+-i3f_^e-Tu~ zNP2^0M41Dz$VlPy?#9M|;RLC|kJC~r_bm?tRZ`+QFjJ1QFBP*}!@R?aogYPA%OumJhwr?!TfF~=TNlIG;~ zljY>u-fAC6bN!UBS35IBavx2-7n7oDRd(Gg-&~N;(-)zEAFFh7JH0H@gJ`zfP^91e zBND)O6h0#0sW>?&ncVI=+np^tV)5Di#Sp=qkb%jWzow9uS6w-n7&vA)JvW|L-*NlG zp0JUti?gzeF0mtnTc$RIq|j!i+kTm2+acweTTz3lUi5c`bDxfXj@@P|t6gJmFO3N= zx!xgZ{$ZMSdSRw@*rxSpw$c?r+O8itJ=-{)qUYbxRxYcye~zhY6L`NG`jj>-5|lcB z4wo{dk<2`&62hc#8?LDnA57RfL#rDa;x^bdIj^2N!uIyn16Zdykw5IZP(XAdZodr# zd8^vf`eKa;f3b%6wOhfikWsG};r?^%x8jK%x35;4FXrX94F|IeI0GTGk?ZKdgV@Un z5}#76^am#2yU^R@wL7QVat3HM_quWZr9ZX7R=OyB@mZ}^D38WM*fslP6-DzAt&R>s zP}O$w;PhPL@CXYirD5@p0BQHuj}`JNwcCd$B^TV;4((XrRwNK?m&MBq(!(#+7q0}2 zH9D$ir)n@Kqs`nWK4qi zs9w|6_$adwpG}+Cyfx)^%@y-jU>4ZSj#d_STp6Hdt%?xp6jgdXC73#2oiP8-&E~jH zfqg9d$H=Vm1Y|#Cp9EG>;o!N;_0ttyBJZMstzU;C}(V=i7d?mldwJ zfmlkwqmu9@Oa4o7iY%oeC6=;}B1<_znWdclrfA^}l%j=C#7P1{<)R-VAd4vK1@c1h zOC){CifX~uq|>N2Svbwt8opb4Ai=iZz0zR#-rEAW-a~L!kRA- zXs2{QPeDSEbrNivNiab6)x z;_QY_DR@WaNvx7`Fhd86fB!%>*Whk}Y#nxb8q(o(0==@cfKVh-=bHS)b?@WQv*=ji zd*UDx0jNfgU9sFj+{MH{3VpAu_zVT)9Ho34r>_DVnxq7Ojt?V?lC;YGm86vg_(yBV zFfGg3aG#5MJ68_&(vAog&A*Hx6MtXB+q@sr*;uD12oCteCTc_W%o?1Afbsc$ORLUN zp4M28mLbO!6#~#OOMkFS4@=;@($sZTXBMI;&yPS+(g(SOu8q6; zU$gQ<7T0VBSb&ZF5h6GgdLvo4sxV+If<#BskD~|}h?9ZjY1~5b-B5oGLL=(ATN#Y3 zAL}O#;cH*>j@9>`G7)(=7M|vP-do3IBW-PlSL4~?uFNer2t8)Kqb~(2^@2mPH7wr9 z=>5UoelGsr>ti{?cdCO@l0q9YWrXbwl<18mj&hM^Y=*%ZoARmRYGCn@5jy=cr7|q# zF?C^WWejLfNS*`j2|b`aVIe8WCf^@qi=B1KhXk#IrIZA%e}Ot{kf^igM}B~z3a|b> z*ctv4nbGtsg4SKP$gtWk)$5TPjX|iDbofIgKy9Fb+@t$Z?on_#lDS7E6@&hPpp}P` zeYCn1Wgi8h)MvscOUb)zh_F)^l^;yxy!t8GC&j-j2x-io_s+ockj**q_vZmed6`i= zQ9qi&gPDDL1cVA}#O0^-X#{{!VeReag01lhN9@GpdvQ>xFn>Zms3T$5KR{iny^p#z zM!eN7Ru;G5T9jc&i{tY!n(AUbC!8Jw!uRq)_?`;R=yNic)}eMSOox~g9KOe>HpY%8 zX5yUMMN&Sqbfx4KY2|%I&We%Lh9Z)zDd}0$ze&$ZPpNK3m6BOe19Bvi=~=-!^Vgxm z`@bbrmiAj`5(db8NiSbW9>GQ^?)RevI=!G0 znoTpy9Hn_iVB_<1(WY0Fqt#ddN7)K-l&w-QN7=@do4wgv&l=ZpAN%@D#CdzA1S!B# zHgAgH)m9gRILf{%Q%=B91_!K~@N2@VSZ7N=n8&I`Bm&M3nDB=IN2xLaILdDJg{mY~ z$QOVg5Rgy37myMJfll$m!>f1E<&_ulVJsXlciDe-nWHo|pfm2V3t_KrFt&#{%F0Zy z*h*~WX(#_47rj7ToU?>etgm6f6x&%UPEDX^ZFK82&TaFA^sKdJX4}LI58i&@*3t9l zGDpd!vCL5lwx$VJUO7Gj832PJ1E6ExNIc*uhq6~W%3#1z_B3T_TI+gUh&A74>No>) zlmmI<8dG6hsteDAo6bcC0*-RT=d@H7k)v#}XuEDrrgl+-7Y20D~(546;b*~U?H7--*XTGXvB}nH| zY(hN-DOzjD6|GAwWhf<<(iz24mT!X)XZU{bxAe`*R(h=u;Gv+Ju%1g0Lp$ z8e|YEG0aE~)$|$;t9vEodB|}y;nEoqAqe^`V?83BXeUDnV+&A5kQDuo`eci3NFO}# z-086Y1!dv>XTPL^;2G0s6P#&%)Vr?kf_Cjp1zKFwq*fvx1kZTA9x)J6QF)V6QkFNB zXy9z+ZOjYIa5Cy;lGbXauk7NhL8sk?AD6*ana0miIe|(NLlv{# zE<-eGzF60A`)Xn($(x4RyGxZM=kF{fH?L+mU;Hyh`%nEXe;+G`L#fQ@>eJ*WAB)Ol zP+mtW`iOJ#9LVPtR~*YE9g*fGckgC5jvPTJA2d}#4 z#gjq4{z@ax(u9DnIg$gg9`w_|QF1evf2X&yI++kx~Tm&F1d6CHpU8FP%f+VqqI8 zX@HmikDxe#zMfC`Q7F}&t)$lhfX`J26lN*5?R?ed83|=7g&XV|%6Xnb3;k1}7ZX&p zTeL(0gdz>?@Z7*vyGQl8kjsY_e`sbc)H&P~uD*RHOf?bACEPSN8mcxttFg~9W}drg zk4sFrPEgY;3$L6}&}8@K(GSrzGt{iK*~hEbIrk^tf}z_e=nbKwsY?i2N+b?A$K$lc zSv{#7g~J40&;6ogA|xNgv}k@*URA>*#(sC-z0nl0sJdaU>^@z6i^VT~Rd~q;39A7s@522 zjPW;igXWyNpFAQ+5}LNpZ4Z;~s9wo>f#Zsx^*96O6lx>DIo$aBtfYZP`{DrFQt#e% z9z9F@SX5d@y29Un3j*lGwpfY{E_(=n`iYXI&Whsiiy~XPz~8&st?o-qs6h-|c;hO- zK3h0IiO+JU$a1-VPd*dgb^7x0e)~E}!AfiuYMOTFtJAa%@)26mEs5pU))!Q*-nG$# zEWp8ZkOinbG$we~BukN2>5+ki{MAcVnaT^d@Zw%?1{R!8wOSw2}(soqPd8n3ViDb?mme}io7Y} zW*QF9+dJ!txstkyZU?SUlI?2nE^rzEbI06yU`4ywZ*WZmjb2sONjl%Cw zH5oU@Nk^8Hx#WUWE(YV&p={M2kjk~gqqWj5A>qEZFBUV>YAum{3a1tz^4LFM&oO(C zJ*Gi3rXWqeVP$kyYShQ}~DQj-V&Scc& z{9wJ=t#b;?tAW!M1=hvooyvVVM)i1*JKR2grr$0%^g~y4ie_Ztr{Z9cI;;hy4yP3D zfwH*7U5>PtjmD0NEG>lM0-=EY|GzOdFpb*q5Q^jaNQA(f>5HzQg~0!-5PP49l80k_ z#T_Vos2?hVy$Lt8F2p7%8Z85CJy2M@cl=3(m+(WY{LdG8jb8bC32E1i2PPKJPBYh-500G z*6qTW4)%J)Ertl&#rGmVH{k%3czgquPXt!LvDj(eUCT8^D}6;fOKG7fS(eZ1`ERU( zU|8p&z+Ub6tBDlpZ-GO6=y=HUWl@wDn zTKv3e2s~CEvxohY@%2`Qs(XYK?<(8xtDxGy;#L-N_FiIqsK`#{ffMa$) zDLJ}ye#mo^qJ=HW07zc9x`2%B)sUnh0;UIBaLZE~_yqN3 zQ}E1RKH!{PZXj@kbRCiV)pdlE4YZDc@}!<7bwA1G>b{g)ZwNYG;~P6I9yOXrGCbp} zbPatfV~AcomdHpTSC4R#bSuY6R3}ZHyz4b~-)gooL-I~vh|B&)G8S4wQPcn{w{8eH z{eOp@|6g#i-VX?2-^<13J-PF>aG~mc3Q@lQ16(Xr=Unwm^>1XTkmZy-1NuJEe+>WX z!K4;N%+OUz9YiTy$Pg7S1e70}S*snt8ZN|3N%hI{xu23S_}dh~<+OuG00eq4ox9_t z5xW9)yYfsm(EGpePH9Lx?~#jz)6dQXLEijrjqZLz_UsF#yute+^KCOu_)L{^yY*+zdRd z4a8OXI*{1L5-qm*`gmZf4HDa^^kn~Cu??|_2#9US;<#9Z%K(s__^Mr0i4sWWJr#t? ze%%ncE+3=|dDSSs8Mm?oy{esAAYSO-i4@^@p~L_vUdTDeyDsr^%uo!}l+CH|0IIUt z4_Dc&U0s_%xh={->&deQvt^KAZoR(YEpvVOhyaLVZ5V~(SRb41PzYfU@txwRn0?J% zXiRXOl4q&r9686KQ1O-7@xJZ|d!gfFgos)wx%nQ0=Yq|xbMag)m6=KM6FcQaN)OGs z_I8jCjzv%OJkZp)$mn!<);w)am>g+rYl^CmZ(SP_UhpMij#FMZ)i=&k)fvN*td8%V;gIj9RAjkGAX=t}O5)CKxYU zMsY$_>>b-vjHY4Bs1IZr{rFkfys@zXwv6t0gPNQY=u*MtG-J-}#iCucL?#q2#5^(H zLU3>=Vnz0)#dm_@%@dyYKD;;!ROrt@Xw2gr#1mT1Tq){hO`mAneLimQJJCT4 z?@T`ds)0LSiuyHtxU;19_gWXLGfhpt*y7Z-7x(|T`x1Dl`o8bFT1bl&X{D0ANVY5y zCD~<-ENuv(?33-vlF~A=W+&OVB4oc+vXeb~GRU408r!`8bB3BTGuM50J@@mx&wIb0 z^ZC%{beuVJmjC&Gf8XVI9nPXvH?pHU;;glE*$v0+^k0+ix?PEqv?)f#dyZQfEJSH8 z#NfZ)Ds-MyR(XFWp*AUNaO45hV2|+~KomFF6BvE&ibL&HVQ>JLJlhih1^33%%%}x# zh5FAlK-%7QD5%xzk`){;#Cy);5U3244{e9Ezx=+kyv>Fp&)-2?;axnz^s8j|>@Xw* z274wVCqcy4J8)~zfHtz=Zy0>+tvf11p3b$+F{lIC?o6+?7X+#RXe1I1L!m}M7%d$K z*+tB%G}|Sn*8DDQEm3+&trd2!wZsz{>^&izW|Q&e*qk^o>2Vp5GM(4 zhR^D61=9k_9$7FgAZy8kX*bNQYrtHWCi0E07)Uorm9hIL?4i^ICc%Y-h6l%0iFsj$ zh^mBi#B3^ZEuKhhSM^W&nYtbXLAKoVEA>41c7RCx<0w&zxwPLY1`Rb`$#8mVXxwf4 zQEB?cbZPqo3){4y$GY@)!n<+{s%K4OX7eM>H6;ql?Jm6OzL}6*^=am0NL#V&oWHq- zlMV=8uae&uS|GhGN5Lg$TshEeY3ZKn_%5?6G)-gW54I@(cBudiS|m|JwBs1aJi3K^ z=l~BKFprYgoLmovBc!&3KoW`~-jR=+7$TJFY{iKMoq%jYk@tWBd81@KVC(>abzEfg z7KCH$0GOyLM9%8$N9U0>H01??x}b0kYh-K>yN7pi0!F(Qw162@n`r%|K6BGrEsYl$ zV1Jdy5fqpi#Q*+93z&ZcH!`Wd`>P%>Du_U%H5#CW%wCaWsy{YK_CeiWV4|^91yF=b zTZq-zge(8lWIb{v1Q!n1pC^NeK-o)25=u)$A(R$ygQl2FZf=^a=ihEW?uX_<=Gz=B zTjE1bB?fj{LG(Nm7}~@ze*^oF+0sT-#7TBmFq2>u#|zti&n$PemiK&s{W?9xr2w< z@61c>gy|0^AtAcexAVt-IE3BKY~(s?FIdOWt?zU;pRmg}Tz$2m@nMHc3s!ZYMY0g%z0hdX zGFH+(jkYKy5Ve!X8G#PCQ1TbqN_b*nWZhFw=@iwcBZ>C_#%3cZFjt(6c@M#`{0?6W zQSWjRhmrZYzyt$!`p>$+KKh+5u;4ZVG$~0_7Z~=}gP`KwW!FeLxWG+drVo*j^aL!A zW8mJ57_kX7E=z0K8RA+4OxQBd@)R)Qj9Qhbx&>53Nh+%UnwcFM{AU$aY8n#-kkIc0 z68cljn!aAresd@M`*fkxES%5}?g|wQA(iX#38JnyO$6+1!H&}etycc7`1$;~Z@WJ@ zT?wCz=;*p}tUomD+=^;!s@(pO+6S6kuSb8(H`L^bZIfX-CpctQw1?g6sZ=I-$9O%G z8OhuyVVIw3t#xmYe_ceo#tBhTVy8%~7^zd_4w@O33l>C3aJP&kJAOs zdFi;eV3)=sBqB9C{8jI?$5U21pM{jp|0o=aSO|MnQt&)GMl#}}dXXWk5O3%gVA)@*Uj$Rs7vg4ps_quzwIZ*quO;C0j+x!E&r{u-{oWMk7er zGx%uG`ZY=-Wc>PE)7*iT_Y$Bi8qk8^tD33CaNUdEu94Es^2+%_Gyl;~lb6ey7|+7K zTA)!1WETLw+7VN;$|>IjHON1`20Q{nD3hB}pp^=TAW4>`Sh2W&n}B317c<>`!=mlStuQLIV`ed;U`4 zoUz=;3Ptux9wR86wXAh3O<5&#{0x^rT_?=21UYyQf~l5r$&tO98Fu}9*bgwPm291< zlhxceZ1ySqvb{vV?sl$?0_gcm&(mJWO6eY2KAs=MQf<*djnliW<>lgX^c|D%dDiwS zD^8Ia4ITaU)KQwAc*EomRAO$8Vz0j5)EVtg4wAiu-*?)oZg#Qv&*{+wtNX87a)v*B z)Ng!~OE7~)yUtpIC?6`_2ieukm*`})|+nA9r)A^+9g@<{sAY4JBOJ%ZYo;{ znz-lBzdHSMKx~d)#u~-xyaG4QP^V#j8+>Z;Fr?G*T#z@MOL| zi>=Ab-~zk>7k~^dz!%}}&qm)uaHH>4B@Jlwy%}osy$f#iohR1Xu#Gj3;P?ZLz9AtE zX!KpsHyy{#Z2}s7+fLNP`!)8|q<$xA^lb|_`W7pi*Gn_cZnW;X1{!?>w2)CH*WW2d zB&6Y>h!%)00HL(MH3@hYf6Yw@w;ak|j>3(I3gYuYN~8$k8I-I^g;A8YeL^fegj+-I ztbEY4o;ZDm=Fh!nsr(F|$|`U0p`mBs;8N9yPCR|#?(;twK-7(_GClpDM4Cp8&52)6 zTKh#K0#tQRmnA&ixxQ>W(;3GteSDtftN&mG2|DMLw~_7PC@}Y)5|>vEh~|*G;QoBQ z%qE{5^sLb1dlYMXeg~49f|ZdS30uJf{_AOnx*$FjSJI(HSWcm}j|+QaH+m7@_yZdP z!9;y-!Imt}1oX$ye)NTCw=hbg@=IW8eNQ?80`|-E2!$Mc<&NNFB)y3X6z-~bp#h6= z>5(E*zI{5ekM>bNk#~tuqXJ#PHxKr|%0Hg6ISctCH)XR4i0NfitU$2aq9AtQ*`oV( zWap?LfYVRlHZ&kxHB(80=qJOM$dKh`aDeR?M(y{~e237RP>L1Tq?vYNpZS)1inC!h zNG+WfLg6!=p3?Fb3`d6z$_;sB?d<%jdu(4e$M=(YRt~}AP156br`nR8?a`ypZxysF zYX-g=y?uh#t=;W6ya-Rn$wQX3{fX6Q$XS(C zF3{-pL=)xL#3THA8E z{&B`wtE1S>Mn4D3>!Hb9`PI*2+Nq05cIjc~jxjH4b{;?r zRuCZaqj>KfLm(?9#BJmqoRuQ_$hErr*-ziv>XQO+37U=h1YsB>%FLC53Vy*y(Ims$ z%(_wx%ROZJw|LAwV0=K)5ErlE7G)ll{8t56Lp$8nu&EFUO59b!ma&!mBr+!0J3xEysIM%U#)ApOn=4CHR6_Is zc+OV})3BO{SugV}Lc$fm-pm1drHxWjcHyFBk){qp41=2-1!od2x}HKOdferIQ0hdF zilWrKZqbKQz1^8&hx_Y zqmzAs?6d%6MSxo&J&_>y!4?Z8xR6s7a6LShVjllHI&;kGg@dmmOlqJJ!!8Fk_URqzT}1!bg63^Ei{;}A7mAAklo01 zRz!QW_9W+{HE{);nuoSE8wooX+Zqj|Zs#5D3Q=M`5%JF*Q%5jRMgm%X*wx8IiyP{& zjkDdCAbFHqpLf8oZ&#B6FO(=HN=TGKKDvO#DMil!HfN|>V|(&SRZ*N2^Ikw=-Y`{~ z2Tf^XZib^JR@wR!?Miom#&bUw7#|4t%l(k+^yz>fH~yuWjL)uLML<0 zH2r(--niZSp>{PUpk2)^xLwV*vP+be$L;7^=n+XyduS)Y>6EIz=`hgS`DG?LT>MAx z+J_0e)RmFl%P5=Tc7BzcKa^8in*Om2a4(!EWv@9f!{ISwP!1R8Uifi$E~*$oo}7#; zy`O~fABxkY@z(Q9mKbHHH?B!#^R(sp={G)2_crT3X)-D=**Tv6nx@JkoIAf@_P%mf z1}4%iuxP2@KXl3iyLCstQ29AerM^&mUeh?=l!9+2ce#`^;F4V20jcys{M(cN+}lgw zM#Z*a1|)+BaXQaw7^rO%cQb(tN+XRbubiYw`h3r4C^q@AfY43l6Jl153|=&U)W$Bi z-rzP>_qDt)`6zv$!upcHRSE6zmMezLn_rc0Ra3~pn#(Jn($r#2Dmq17556kxObUx7RNsnW+MM-c`zHVlg&Jj-d0{cH}UnOJ{zPrTJ?)vQ;OP`qZuoG`2U6d#dsZazVWWMaD4@xeWTs z+%3eX-7N$|5hO9DmPuU8kEIrjjtEy>2T7H8NDsJ*Y95WbLs3mk9t#S%S8owY>>kdS zLK+e(vO#&Z&n)~tB6O-j@1`&;*JoU0q5b*J0z)5xYo6RmVZ8r6iSZvXjo@o9vqID` zXDdk1qc!bf+{F zG8|IS-yz^_WH|^|@#&&$h2ywrn!c_U@jKa|iHv6A(myZ#^g|)Tzy~WY{1X=js^s3D z&&s4!#6OE{p#yGnP~?1>a~x4m0rc$=)Hy~(i6nqZgDK*?Yi0i1H8iJxwVzoF88Oe? ziAL03Ku4SDij0dIyNNbj!?lJ>^ojTe;xf-4s^HK6B4n5!S&W71RDk|Pu3QOr+C)Qq z*&s#>xK`M5`S@KN@h%8pQ6-{MuKubnn_Rv8(gvki5#d#98&pJ^q1+4y^#yQk??hP zBip~hcX}&h!Iv*Ylg8gQgU1Y9^63Cd1jxgNI5humgA>%k;&B~Bhc<4)HGWF18P$5^}zA`D#8TeEddMJ8|Wo`wqL%%2Ja3Ir+0h&x7EOBNT^WtWRk zlatiazrglg)nG|2PifV9d-+3&#c#;uv56k&zjY^5KI@!O?9{KUHHNId6~@z`Yg4U4ZT z?5zQr&%19{k2HHYz~K}8vmizIyJM$%p1NsY*uF^>5sX&*zH#BmE3-wHTwMwT=dusl zjR@V1PvBi_ag`bjx-U3J_UsySc==^`^I^E@3=n2i z?c58R&ddm8V;n2gIiaRA1<6>)u_Bt2J*oKDc8BfY5aCX<_|2$I3-^j~!rv|E=7X!} zZm~FY6wD|bYj!)SWw+s-0Y1JJgb0f*M_hJ@(>!h2uh-C>Eo&RBAwH2>j)iZv^wLjopF%sZ&h2r(s8CRjmB zyQ(kt9A`uetP`!288hh7!Sxx)Q}5N!1Uk=xfuqmHKr6?N4r32EqcBg`Q|+< zbEbq%_C@qYa{2@0^W7n*KS0JiuMQ&_ui_6nKhu-1EmV2VM*J=T{5=?(DAJ!)A|V(e zigP7H0L<<}FzYBWmA^%Q0?G%pQk(Rrkcr#90F{LkdhGLo=DkPQ_kS zi7Ywk_oT2lfjlA-4FY+|PqDA~fmdu~`#p@4@gctS@bzS=Cm;Z4RQNf3|eZpFDS%Qg-#mmaSRgiyc7s$0M^+YBHuZsaVi1$1jfCT z?%Z`^%U49{SzI+g42%C%&>5NYD(!Lqq-^Nq_5ne~>C5a=Tr5+nG&>GFzn8;nW%1?I z1I_ZzYhsw=QOgESBFbtT>)H=!itdeYiRi|T7sCGah*Xc;R?8JnS5KiN$y#Ga1SCDUTPGT@q;7*Ya0lCG} z;$TCn0

Emq%}k1Sd3~8JoM)ZRiGjqI!s&&StWS->k9sx6?@Rm0x>Oz8@{ZWFtQ4 zSTm)e+SiSFw{{Qx9*r;`JBiRjr6f_t_+%3W|2In6wD0A!L~^SIRE$Txmj=T|c&y%q zryPxN%k~?dv7fA`89gHy@?Nq{Hh!E-Qu+41WoW3? zO8ovhtM0|o1-m-~EDw`X1iCuAe>k}AbP%)ZIR34}=z(NnosNDOu2IrF>spwUQ0D;M z1d~x{I^7Vra9yM1_$+QIHgaHdgll!fi`bM1p85q;*aDxdi6D)tR6vThTg+E<35%SNXCZH;;RurgMn z7V|aO6!3M#!>cznyPt%Llt z!ovqJN7+q8M5-%wlqWU`((tk~e;_IAa>l&vtn}W=gJjF%JZY@h(RcKa^;h{#3_Z#c zV^4`@$l$ENd!X7Ggk-=7`(3vYMS9-sv3RuZ_QtP?{&vDw^Epp;MaMC*Oq6!p@aMqK zT09&`0IsJ!mTw%n5?qkZ%5sv^n0yF)Gu(~0x*Qu(Td=z^d==Mx%MYTZm^{Rx?~Hp> zj=a_!Dv5H?AJmWpW`O%`9Mg};gkQNDMnkdv#f8JP==s~Z(_z(C*p47$gD~%!Nc)UX zkoPaZuaZ-kYdrIX$wX&RDC;q&kAPvg{iH(4xw+UBrRmq$T2vMnMtP3MUu?+6>E(E1 zYR#97eerQl$7xN2T2&JCuk_utT--V9`gC0cgOP6M=HNW+Yq9(Nu^xEL1*~jXTe@@p zQ$~D;G9yohQWg2F*mIOU$}`s=&F*?EpzyA$n_z2pQe7H@x>k1OXmhhrp8A5I1bspp zKi#unOp*DXHw*(sIvNSxM;W5`YjXcL44J|yOIOAyj+pZ-hrNgwHR%oDzH*T)KcmVU zuR)z0c}(exP)npuTzhz@Q7C)X%sba&%yai0_mFjbwsQyl#OKFK{NofD zt$$C|2(%sb^PG;{S7f!|M9&+f?fBpIsJ9c_mfG-1|n1Jv^L}P?0w%Bn_l~5?{TCuZ!yTv zJ2JG(n5NI;?2i(^y;kFk4VC}_qD+P5I5Tn$2FqQ;me`NfKD6tuw6l{N-?hWN z&iO3kSURO*wK_4ZdENoJ8m?q!1R~7G?XEWZU(E6B``- zXm5};3f+Tx;S*Eo_!&la~1d#Uyx{C>7YaQB`I^AQ!S0akS5UW zm4c3e1XY8nNS7Sb%o`pi?n)iGI(cg?zbwD-Kn%E;ta&tCZ~VnanvnP~&YfoB2(vQy z3u3Sfgu#+;{GCsJ$w#(awOT5{91-CS!D(!0r7{~c0F0;orskh z>k_{SS^Grq?&EuV&9j^uO~=F{e$MgHH+t1lBh2^HzlaLJT7XZRI6Ntwk^GDuo}9}=V#5G%fgU@5WFZ#O(z}E6*!GlmBl+2#dpf7` z45{%%Np1DmT)A*9{Q*LL1`fjVh~&iTe04>m3!Vd3+|`1YZ z#U?P0xGM4^Fllp;YH2N|Tmw1fgEm!itzo!_kizYimMQJVl(RQW-Z=!rrHKgzdc{s zdWaseXzY{r3ih9irIs!-PBmALxWpZwYUbaTlw@I@Fl+8Q?9f9=pjqZH+uKm#`WSg51ojJdvK~P*Dy$^M9Bu%IL-umxD*sT zR+3p8BUtcsH+utGI?@FXV0z-n$e^`(S{zucJZu?54xS#);okV-z_@xyy>7hCrqU23w7>XjVPDgHQ|yI(24!|ixy#Y929*vep-cuuvi1;Y|g z7zIyotS$^1j{G>!YNQ7Qy7!(r*X$+*0tSjqbBJ5`AcQ)ei9grcNdg(X8U1BlLM!EB z&Lb8uF$X9v4*8%0C=gc3LPGWLm3EQk7s)2uGNqD*Bx-H1w3mZFt*qWbG!dq&Bh0P! zHZd3|OFSAziagb%y>k6&+4T;Se!m`N@Ww%=_rb8r`4bCr4**s{yI?zt40j;xm}(0a z5yS?gk#~pMkjM<)wwxji{NahrNgx0|abwW6k!Z&RB+4R>OxA}#Z0bHgg+qvaCWRRH z2w#n!1hk^0AHVCYls!dhzp-npD-qWp{=4xz_O7hG&!jaXBB+GY-xOd@9khsmNsfJQFEC(*O)?8bnyW*jnMZ)IbHnxFB;&m1M$RFl)6=CZkEEUp!C^7hf zokg;ZxmSRu1y)orTWKP|bt|ox>8RqG!9%D?-3^vfD63s9roswk?9fR1_SZ=2Nf=3w zBSz9HvXPVl9!Z7c-alzG_50!BVx_h4?$eUK&L?Xgl_c*^lQa1x%P`?rG$VVKT83x= z?_M5uG}Q@+MM>t<2T=#f_q`82 z@vJswCizoYRKWqvb_wQ}bKTyiPM_38)Z|nq)hAV4W^j2k`)H3ljSd?2W;CU!`HI>F zHrhJ$_u`bg#tTh3oyIfYGiwZ`rq?(a9-iWda49k#a37=qLxAk-|SJLsYW{md5i1&g#d1yW~czs#z%^ciP}$Mj_jR=Otl z_82k8&5IcXrE`2AcDt}&`=M1%&-o`n=oxILUvra9@@-^;u9`ho|7K3yGoV>g<*V$~%XtZOE(TjA%A@EPna5q%qET0j$1 zrPn>iI?91*k66~coY{?@vVB_6Sf#rjC4{H?V4t2fyGdrN-M!hX8|Lwl)cFZYPK;J&`6j4IUMVv z{Q7JwM}^w`UiC{=r?f{?cVY9!4tlvXeRw&(QO?f>cZ`+xlwe*h{adOB-`obQBGV!y zJ04%O72+Ld;~Z!S!ms_ar&3yO(Dl<8=im=jU?fg6q2{_T4V1G0sgLyw02W*%LQiQ z#xhX|CjkgnhM7u~-6*rM<#4#2YO2Ro00k#y@6kaR4_~;2>rJrulN#PWCBVldVHKd~qns^^!RwBhUFa{F6LTTHNNMO`L z4Sm?@SR@I^0s){aitHjtFo))hgpch!vKbYy+rMB0pz!xm-a3*{1Q_MXg61gY2rMT8 z!Mk+mE28HGkm)io6!zYkj?5q@oQ@|HPsd*PR`&V{(BVDAZsI0pgW=mH0&{@`qd^=V z0GwO%NZ=!UGPd&}&Gs-N?EjhN0S9}`sNZ4{u?t1W!L~-bZ?07N%EEs4Fk(?VypvLPlwwKNV>?r~okp*RL5;4712gGdqr zDq8C)xYpntNwC~;7~s{mczKr=Vamgi6RK=hjaz&;zFK6V`jRv#Br&TiA+*`hrh+&= z?cE5>*|CG`P1xcOPhAe>ihfUVk{=As4z^&*C|mBa{54Thd_=+i_opK>ybI`bq1vV@ z;i1}OU$O22#fk9x@zNZHtP>AQET08Ul#0L5(Upv_U+Av;j{(aCA^uSsv>fta_|l`PU6>&t%ebP%YUcK3n!9Z)tq zktoD4>MVc?Q~NbHVZI+|Y-1U08d=jyyHG3KqTh2*L|aD`Z^qg*I^Gk-(CTe=;z0y? zS=wb+<9N7|j z&aKtBT*%{QPBlx{sVV_|mO5?A@Hn@Q@#zKGQ`L;3OF^-6+6%PC``TURP^%9M7}g6z zomYmjU#}wY_*t<<-9nK(zs(Nx{^&hOb1Pt%9#-~CkWHomc56m5>Vg1Bvw;EH-(UJE zVgb7V*iHV|C4#s(004yjWnU9RLKUK-Hfb&K6@gKjIMZz;oLa$dBy1l6@*GA|r!acN zCCXCRt+T*o5k&cluvmm%@_{dHpj1zaZN)xek1lkTh@8zdjkv9OmR`yyt1wNIz z9KlYmaE?r`cF_>;g1|&Z{>WA>>bc8o=%!vzW8$6Vi(4AuJ&@NG1<9}>2 zO{eHhxlT}C?agaGhie%Vx)&Ow2ERA7#G`a^gM~T_)(K9*l@Zf}TG2IcUB8>fF*g5=m zAX`p^1ZMpwXGt z5*?j1@dD;XznHCfXvj2At@BD6X>UAYsXi{E9a@{GACEe5NpeiMSHl6dxf+%?9By3Y z@y`7%97(eeCVG!uvoRks}U$75fXZ6K$NJ*jHJeYMk zTGYhOVo(8}TKgm|I&2(E?SS5~f%~Ij-tC}e)7<(==9#00H*C3O{nKZeYlJcvCZ>Pt zH~|^)i{x_0#&?+IvIf!0oO;*ndWn0&a{JSwH%sbvZ`!$4Za7*fWk!wUI<(6sEk6m4 z59b`4W~U?AKotNl{LmybAE!tcyy*HW|8MMsMrjn!XI2ZGftH6;3eAuh*;xccV%}OHf1X*#RDV22Y>0O|lE& zHy)&3@QvGEl8_VNl-{ay3}e$SMY9n9_)6zizavA~OY%&2%&fyWJ!yCJ;pNQ=v!`VX z=pNP$#&sWwE9}5ZuE`hu1c^7TW}|!scw6n*+gez&FP*1e9;wBi#Iu_lkGPeTcj4bk zEY_iBBc6Bm7Ec+b4C>>1W|y&foh~ev!R=!~E#YJ91vgo;p;ayd^mUP{j2>+Vpc=&1 zQA4l{!Ow|uKx~ui_1#hcan00MN4q;!_TLwR@@XoF7Jve?F|p48JS3jbg1Mv?cCgVg z9Ks#((62o3WA0rrJ^%j-Jy*54Dua_&k4mtQ5_9y`lM~5a!SI73bX)rv8D9gKYBBI) zi~tk-4HTrF51*iK}Vr~v1>(ozg2!7hMjtKg3tbqXG!$RiUr^F9)AQ!-QF{0eg?j$QI z0FZZ?{ER&;>>av8#(oN6rO-&|SG5_U6hVu1^3yBZBS~Iq-~rv$@{r<9=n_9&e1rap zz+q$wE=3?fZe)5KcZEtc6fi1V_2-L52#IRe4J7J@DDJU;&Dt@OWH=4 z=ciQ;;O1s`5l!jDAO=y^6O`pvMVADIF2S8%E{TVf+Ze2Mugu@L~is0svr0mIxrXL}Wy>88ri-@@7og*b$np!(ISD0OS@xbcw*k z9DqM7HuMc7yJAK?bD$Q}OtxhP8~Q8hmN40R`>r^t@DczzAnOwWq7p_56aDa850J7) zmBf=k;W%>pF>*Dm416g|L;AI?*qIeCA}#eW>|)-wn*vPqK0^tZpeb^BQ=2HkPe)3^ zNhaBVy{C!wsW1xar!zqw0wCRh98#8#g3uGkaTs|%2_WwdrTxmTqog%0e~nZlK-ZI< z*#>zU6M?`MC^|Qp#~@^v5TJuezJ4Zi;@b);$3feZqe6)LyN0|62Q~?A1D}Y#NJy7h zRbvpYhRULDV&7+|AXeU8XT?)eX?`gbWx;g9siVlu9wb@Sh__>VLR%g>g&T!*)(FLO zG&0uFUY_!X*`}nbL57har*RG=DRp$RD zo(tv2ekdKs-0rQP+TQ%|eZEjjUbb{qvJfgFw1dq-zT}?w+t+q%Yo>h*9n${DjV=^^ zIPy9y?u&n{nbC^nA)xq{RDU<)fuO~Hs?TLAZ=x)L+CM}cW<~j(+@sq25FXG zC+na4VMOoQzfxu%9*0X{{;F5s59`jBaE&vYht)^fGI!hNSdSLAqU-tTFu4UcL*}sB z!|;fC?F|0bRi!;OgDrP7$G+4P1Pz}SR?A;666TWT5{l;+yXGHLJu9-C&X{Z)*5o`N zkuPtW|FilPP-L(3g*MqntIfFhdws{)Cz^c1aCzb7A4`GzOopTE7Z#T<)MLHQxDAvVEZn6YBT(PfpKW`F4_PPLg|aXdHs%fv>y_J^I4n%-eWSkHTH ztw$D;T%Cel0!Ahsb@HEoOu)-8tO{<*a#t9WN$|cv9YcW%sAo^=G`q`IP+W^l7gE26b2W7?!kTf${=Hw^=?s4{@ zx3EAj_+``{ja$5^{SC%{g1`Lv;-lXK-OoYJ^jX_zq=@(lFiG9fCEugB7sxCD^q>d7 zV9BNH55KDf`KEfI+$~NV$JGPGJA?iW?a&{Tybh4fn*kMf5Q3h+J_%-c(B9-)H3vVm z6D6b(yQz(g@Bpeoc1qi>+l%bKM-V`gh%nWpaF(^lrM6xZ1uW!>xOG)|31b_|GD;H5 zA}ph%%-a1)Nt<~AJqpQW2|7!dn}em7DG<1fl^}tfFtF_Nqy(|NSt!wV=yTVJPqMUX zLbqH7pcR>vC~!ze(1%ylO5pZ~&3*9a-KZe3`oSl|<30u8yq_p%q*+h?60{-B7gAV5+W#dZiFalCUAP-hiTCpTh`>ZN0SEZNr>ynxE&MDK9 z>N7v{U|rwOe7hfwT)>ym$1Kq)Ax{tZ!aUgJKaD7?b&VSBBYG@g;c#aK)hTk}@Bxr7 zM=l&@M&T*c8hi^S2SdrA;yG-;1bC+qJsw#1z3a98m}##fU-aOO&ciCnbk-Kh9&pBN z?Bzo?fQ03ly4Y)V<^5!WO91gK(|N?HCs-v1Nep?%V!%*>HYEpdA&bw=xXN_MI5f}xh`Z&#R|ma3P3%OcY4n#&)y5ARuIh&gQ{6Vf{S)+k+k zeA|~FUq4Ht0u~zvv$>-zF=Zt=OyXcUA6Ps(;;%-a*{sx)e-)h9y&};Mbsit$ zQW!E!yMCvrdm-!XysDC(q<;0XcHGi6i)ozyL~K}{mSx1k(HET}^+!Aw?1L>-XRXzK z9IBNpNR?|_d?%;N&Q=FWh?IOC#3~LsOHgm?b$OQKeJYS8aP4=Ok)7fz8lo@%SgAVW zDz1)jZJo0hUXJK}-(43bw55<_l49&zYmf3QkPV49e~&}BM-qA|&r-a!{n4u$n^no> z37{Q!{BIXsLf$DpRC7W|IK2;IfoKy&rVFI_$mc&!bO{5W-_%@+$9w^D!~cFi9efP` zyLP%r)!6?rKOKyv|Aw8eoP`p}SH81k7gy+hNOQR?!|qVI3_AzC0RM45?paW^EI5&Zj-OTI7UGIfK|@}UrFED)*JIN?&h z!{gtvdOM9I}}yD zP3@Dg#g-yi(UIhn#(>@!D$r{~u^Bt#}>-ZVvdnd|-+W{E&2(&xkr?YZ7y?Q@-1;nU{huYe zBrtcsr@7oAHRA*rJtB$@@O5%a^j+tbBiQ~VQbGa~+-GU*&iM+t=<|q$UbWN(qd^AW z(peHV(VQj%b%42Z+$SQV`smv#m|OAD(IkF8VNDY5xA*i0ho^Ha>E5#IWe^J_gFHNm zzJUZzP+j5a9Mw@|wE^osLIqYY=plP0K&R)N#8+}r>u3elIxS?Y1W;sIs92y-Zt%h^ z@wFjaC4hqv_G6w~)w&a4Bvc*oTXfuxh}M(>;vw+lO&xr$PU7$p#Ql92oz(w?i!R3# zDD@>JVs`oL#GX8aM*dI%85P|akIIIrgYbN$xN%W9xEGUsthP{yHssW}fgsc_(m3)a z%Bpsx>{MN5jfL?(b$Zj{ljA+3hO@s}VaBGncl}@=TRKc7%3bw3hmpr-z|>)TxhxgF zG8Tgt%FxHzvhXfvNATzw?33m|EQvypMQu`+&ht*~#kP3STrEYN7Pbs^^-hfPc-vwl z12FsVS$9XSry%I=r3*b_GIkxc;;N8V=>0FP&~}1W=sH3x6i22NQh>EW=$~4lzk%oS zFe-qhGc*6!Rb_gDRqkh1*_uLCxeL!W2~tp2>dKimlD`c9^gD;3vND#eto)u*Sve5z zCAMPw2%)kQv-&UF{h_=U0$gnas>(3ulfWtfih+q~NjV)BlHX$zO`dgFnU{5MJ)Fsy z>z2Gt*lA$X){Hc{*=tL)JPRBxy;GUCGBGOnhhN_4I%mzCvj$;r`UNXa|KeLy{PRN8 zOMTdGri!>3(AtV-CfFjGd-v?TiURjsR>~7MmQPBl7ci}LMzUdpOcC=*zSmsYofg{I zA51m=7@*5h>@=d*92_y`)j5Bte&Tz^AO7R6j}jhs1#0bLsmQ`f9?uCIFBxnXeMK9$ zU^Wm}rQ){qG^5;TK;>b=kdq(mJRj#L<`==Bl*(#yOvJphDEc0-MGwgk&I}Z9V5Y$7*SaFSz=d$AcgCkz%JbnJ7^rEoF@i*n71dMy~ zdGi`+(!3TX^hrtqH9mWgv?D>1Nr$`~1Py3&EQQ@l?0p%&pX|dV;v*0%2`Mh5&OHL_ zsC03286nW+SHepI%ty|Vu!Dd!glNjgBtAmI(d{RDOMw^|$M+=ZFff{R{L&`<_-{L? zi@$>&54PE+ky^zfR$5+N!#zgUL(Z18Ir^c2I*WGiUfa?R9;$7eAAZeU+40+od!;He zBpUv-E&Qo4jU_vJ!S#uEw80TV;)~kP#Fu$Nar*c){apFHun9%cfr; zS#*SutbZUvvbf1Yvb5lkte$|?kSs#tOFD&&ERgtukduH}L$H7OI!Va?C$H3oyMb-J z7_nKsB`Z#@E55@foy0V~D+rd@%e;WgcXxKkKRQWXzH6JGLb16o+6Nz-Hdy9zfy1zF zeq~lp<@9JT)XnhGU(AE$^=qAe*6zN4mzY^@){ct0R5Gnk%mXS(4X4>tXO3V7}T}J8L+7GvbqXqf0hcZ6Kj!xuUH<6Pr-hG=0j=5E49= z(`Q6{*`V!T-cRR#=UDe;AILQ41>$U`&5c=0S_-Ed0+LeA677$R>5XwwGpvh8&x$nc z(1|^$aL84~f^$wUElamzDAR*}R%ze6oP9^+>IQNH#J@LVgw&~-kG#bPHanURq3v0A zMbs)3$jPI!2i(@!+PxgYZw&7plRRW$`oiC2ZjKvPx@BGu{=Qhxc;% z5iva`CX-v@(qE!gTd-U-zBFKyyKt_HC#(Hfib(rrt~Vj#5?26w2dF)DaVSvb70e9+ zIUFBKd;~HwW>bTx7l?i2D_eMaWj!GMnk9KW_EOFHmH#_=E+-i$y?Hr}AyZ+LaM@-a zR%V&hpXq3;DQVEu-VePI*07QiiBu%K7tCZ$`37Q$I2G9Uq>Q}{a3L{fSYa(GswTtk2|FB+E6Ow9Ph&rdVO7y{J1x~lQ^_GO~D~wi#bgsWgFA@mDx8&>>JBpr? zrBC(@CDxMpEF}{6zZr<4PH(;Q`|P61T895HauJH*`CWDqJV}3tTzo$H4C!lvQR^`r z-%$VUpD8Xxx=~?m#tASYFxyBo5l=&*=$0}}xd2iu1!+J*%8MYvCIfBSf+^R#f{?T( z9|Ath-|_!lux(~$!cG79?b3MBvJw9G+$)9g|4C3(UT4uhg6)Cir#bBCWrv||<{+PZ7DnqO?J&Kamxw6laiCjNW}*YFhkpS!D6tb*mLbq~5RA!Y>aQT>6Q}0T zTaB5UraN+zX764!6&kV+8LYgy^s?7ky?emonN48abcWW6BG}C0lE~)&iCp{CWpb#y z4#l>o3#gwwGK2l!(wZ)}8!6=vGAlQV;(TEF6I%r#o?yNAYA{{Znt6$tO_3}5r`w;? z!rWX+lrx;K^VtR7bNcCM*|(82n2x`~xIp}EcdTNQ;1}nC4?6P+-4Z2k%~{SdO;(hX z>E5PP8f~TD90NxuwLF6(3S3ji_QcP2>fUznxIb1l9+mvA)&M2_&fMH@>1_pos#ji@ z^cxNPNJlL*mfg<&VLbX+@vTu9UM=lmNG(S86aV~&`mdb_zk63ZI2{ab1-ay$&4xKP zw|_$e6_N*1=`NdrRJsZsIF&9gktCH)Bmtz-t-DsxzHAKSRqPdGUK2GwzO_ z*79q|JH_k-FZ!%{ApnG%g3BQ{%VA*V_lDo-*L)KGJy^=Y+I$?O)r>SLD$~dy7D$T7 zhUP#DErCiF5T^}D;fe?lFx?@3efG6e%NS@y6@tnfC=yIzoI6>4A~(cB@xlw-m)A~)^G)Fr`5gi( z+`Zw#Dbf?RlPB_QByy=bd1|YUF6Up-&8M37H8x$c?HG3u%gUQl`LrOj%~mVG)Ph%U zunL$PmqmY@Bdy(oiv4VleKR@aNIfERRX=Q`OZSkGW>}%Jl7+umoZ-7OS2{#@{)sx@ zQ=oPCk}9D#sWw#!iA|3G5}WkFViRhl*u_?QuCjF-D5Z2Fd`Pd)9181);{D5rP<{Zj1)EFtW^ zD(t_WOH*jxR#sz-Wf|M!(r@zJV*C8Nfr3-M3Zvcgar7g+of_K5$7Z5}v?ffn58%(e z47(Uxkrq+?M5y+Z=#2WI@>9yZ*-*15D> zg)xsiEmg+XWLon5KPyiz7elxT&1oQ3wmF>*UCy$8MmN87HOP}=sI5lcH3c;k%c-u@ zqB?%r{>>-N?OYobna6FOvu2)?3X)!o>`2NVtv90L919b=XCZvvFTC1{6ZJKz z(jtDl#CcCVchXdA9rO4(&@e05-ai0qR*hftb>wnAe(TASb~ow9!i#MYdfLIwmWK}g zND;2?UyMo(Ny0BN+2A)Xd=ndLckr=vTlnCX7V5C%)VWYSWI6ZvjlOZ#B`upwMvYti zDCf5zi3X(6KuMzDjRi|g0s6R#b!>)SVrF!8q8zPKa3UznJ8CGVz|CMILze=R?CU)T zIoAKO@5^ii#8Emca~U~~%=Hrv{?M-{uI0yH27c9nABD`tFP;G&vCyptsD=Za>0#CF z&x9K&=>`a9_k-Y;y)ThET9|s1VDbgR0wUA}yY9-*kaJ67mF1@>sWBTUsy}0QQreax z0ySz7c^s<82xO;A4(Z=rKhm@rJS+Yw3wI3B(!Kr(PV9XR6~2}yczaGN;9qwR&7toE z@n#MRM#O;>^NuJKBvwClaj&3h^NS19y?Ex)f;|HfXnX%4dpL(k9p{!_FzI#_sN3@{ zOxy(b^u2SnZhEnUCjnmGy_zQp#RkE&EQ~$LI93>3lLX@sjF1%Fl~k16l^{AC3W|kd zOn=F1v;6d6595p}GKdu}DS)6lWUCLtrQ3g-Qo^eMZ2u)GKgjN+bU|ZDC9{kHCDI1b z(f25R+#_C?E zkWFiSyu(m@B$n3zj|CPxd~aAyKv?`WjYE?bV`hORi6iN+K#zzl3)*e~ZQbe_nUwjt(V0K3L54qW>| zHYB%PMaMOQKh2Era)K_j(i_VCqNcg{#8$w&FKLTwqBg%{8X)!UUHs%_K# zq_<5-!6kG29D~`+(AKOfiA3+C^`YG__SuO|$5}IumH6$82-a-MH68R|$le z+0K`CW-P^k?j4v$&}>NW)4FwY&-D^DiwxK2Ycp~&QjI*H8-M<>yG}_f_;3>{XoMR- z7o06L7xGl4drC1AZOD2lA*xCHHyq7><9q#DX&(Xz~F2__fudB^Wl;n5rW+Ci%gK@Kxj z?_?0Ne!`neb4a(P);UeBAT5gKYG8-Ku$^%uZm`dE`t|bVZDrw|;+I@o)S5<_@uzsR zxs&DC?Q@}{$%uX=W`cZR*S+j39&iv@1{e%OXV96wSUXunUT>h7F9Zf2aVz>f7{ zNSe#-$sctkSbyO7bm7?8(=Ki&+>&>5Z?;}RN{$$lneVv0$UAS@;rN9eLz_Wzx!c#J znQk54+A4>V0n5xU!;f)V_L8n$tGbJ9cN#Psa|6LPa^Y9&Oy0zA*R4Yin*@Z5fD_Uj z-I3f}Y~Z*ia9@p$*HOb$o!XsGCVfL&vpOYP62kN&6n)GcbmLUeLHoC%_72%l^=RZA zT^caNVXqd=8;@!jZ!!v7(6Fe=s~foV$>FA5mDi+^mPK7@FLwX(7swrFd(PjzZhaNGr8tn;H(>bk zh!L#2>aqXB-j~NywZ47VDJf2=OpR28D9Su+L`mkE%ngPpWVVfE$ceOLlguQULJ=~b zl6k67Atc+FA=}h8zW3Uj?6vK4p3d`oe(&=m1;E zW~jar9c^n@S+kejeD!1&JPA898wP%F@X*O!K%;q3{>1+2``_ed z^EwUln(T6$Tcy*#wuy63ezqRa*Lo14t5g_R>o@BDBFK`5%Q(9EQK%1tV7O0%dffFQ zH9x&YWckx;y> zwScqM_^---iliQOEdJhqu)`DIf^pDXBfAYA>k4wleRsgBDU$otE$ndKo6rIL7va1& zp;b{7)+?F{&}~nVWUNI>9|bR+Xm6Hq74xn-F<6!bb&e?ru@A|Q#Xnq?hZ*VEgC6+` zyl%NK)|X0!otYh;CyDSFh|BOiNrYDSF|!2jb6{f%#60`Ejj7(gD8@!h*UU^{h?{fv zVY6&U%1k!4Lga+J$kj{sBA<>=*W~TjN@3M}L0o=#9!JJ5;8_sT zHKbA;&`rx)=r;b){@MJTgnbnsNKNpvb9hRlAWbu^ub5J*YcN|^Oe40g)68PndM1N2 z*1GqHn`vr#lEM4#%Pr&1UN|Vx+-!eW=Pvk8T1(9-9F5rfQV=5Kx*TFqwFmCD7HB*2 z8K<{ce`9advUE%O7$G+h<)7TpJm(|wCswfOfpP91FT56Ji(Bsbs-KItGFk4BUoL%T zRxmmLLn+*^^I>I~M_AyYvQE>c;sHs8ao)+c{*3LNLvJGAKNOgL!hz~*>fK>S9S1x& z--_CL^33g$)x`}>8snB)qqs%|V=vBhahH{Ln&gKaax}Z9(%dVyT&n_dBu(GSb{16W zRC45wI(OpZSlZ}4N~!#gzTcUdlITWmExiU9mf6+I!})_k4mL@@AnK`$>y^^5P89Rc zQYRVl-Z?cLKV1tEmRX&fo*SsOoT~4zv8m`4J8RNpy{s8$?F1@ac3Ff;I8M{}Bf``> zZwZB+Q1HU(FjY+tM`dWFf+R@;?Mfma3*4#a@0Hd#Lv=3m>zutVhA=@|?q`Vy)FYBA1e~(SC7@HUO>Udj`7%0m){!vPIDb;Mgg&q_Jgn`gp{g&424u?KHj?YwWtrV91;=HFFF3)LGqbOnO*6;{6t50u~S_7Ox&39 zd~e?s=LPA{sI~)DmfZKe_ffE;*%|Al0Ob)s`1KSeC}t@FA$DMAgH2K`ZXcaM%BI&5 zK9_d{a5EVem*wn{g34V=W^JL5R)~G`81G#mu5yi(0){kdcRw7)fZJ)*bRDyNd{}9yW{`K{2!C&%$GA8Tq$5&Ie3ICbbJPZIbL|}Rk zqv5nSp;dwe&a#7W05;rU^g8|*{9G>?ECMQ2?uLie>Pb<6LYe2`klK=hK3Yyfv6?j* zj0+U_WQal+hl#?S$GXb{Iv)Pb9fpbLhHRDc$y{ruT`D-0FPb9;y=Y3hjq}7uZ9Hj&uZK_B4P{A zddsBB2#_HoCRpRvqu-$FmUOG-E|I4x27+lx^4|W&DSR)Q6&`8JpxR@B*(~+$b)ugv zHHv}h1VYc{#rLZ{;0FG|Xp%fh;0A$+09_i?Zn~rR;+Ct`E}>TrMC=PD>JI`Kjh12B zzK2wTP1Se=l<6sl)rbWjLK$HGRCuS}iT~<(;{XV&Wfg%bHGn6O3F#mO_troUaUZcS zha^!Fxb_H6*LU44WT|P|vW=LQrh~Tr9Y-bizagn|337&b#-m^wTrB$%P5k z>Zfb?5PtZS#eHDb#~%DQJV&LaO3IguSiTT=q9i>~oume1es&#tKA_}TNmULrMBJn) z%+Ya%JE<$yp=8AU0gCBOZ5W@)uC~($=(oG6y&nY?)-3lKrkW-)*@+KzC`QI%PL?@FdEz=ZWmJ+xn^PiH?%d>UT~p?k zGY`xgtlx*dZvR!QbbX~ux`fx|HHpHvp-Pv^tvY&v$G)A5VABXvmUNlVm2{}Eh%#uu zsT@M>cJYf*D0OZcd*|nkNh@G^pxX#?l7J#6pG_Q(@y3{^mSVlUbg$XR?ZvemYyzo0 zdYsamRr=D@Qy)w+ZAB*5nT@IUxj1{6(YuJ%ctm1w&!C5E6N zca61S&1JJ|#-GJXC$kn<$DE9q18$KRDgOIRpo-i*YK23kZ*VXxrPGGImGU~VMs{Uo zYWcYxfmw!#ScoRclT-{!tU?eI=1Z#GWx10{G4?EM1n-25=7$J2cp;NCpddYoJP@p? zyoM|ZpanuEicGX{in4V#cnAa=99E>T)52oDL0H%>9;Ful}lC-xX(%Z|ML0;c=Km-D#^O|JP2IatA_%tT~S4w^| zV9NgtIb@=;h1|7hYCAH&hCW3Oj5~41r!SOmC5++KJ z1B!_od*Nxm@z-8?Pr3$zPlnQk!)&OVM1f(V%K>3H7^uVJO4~SHGQ9*GrDQ&470FU> z=PM7uUlj{ENLV$%OD%AB3xw!GtOtG>*^7h3w}PNpu)FQw`Wv~jEJ`)Uycc!s5+}23 z_jy>^>nj!dunxs61m`@Iwc4jY`UGUXZ69inJZFjsuA)Vf97bu8asbjDagkQ#*@<6B zsn-_Lxm=)OwzAv!&$Dd8IlB!6k89lr7PST zLMTj!Ezj5KMa|b&n~%A$waM0R-6G8ksq%7UA<;^kbTJ|Fy7otHn13@>W?>qI^T{ zliyz;^}J3}Ug+v?!=^I?&!CoL!`p*ZYySWhbG`J3x`o=0J9{#h4P`&u-~1y#%MJ== z8Ht!(FdxD%n7IjJF&8xU<>1%L1tfmG+~(%xAtd&BMsZ9tEjh3r*GyP0Y3sW>`ab4I zjpXfq+<1M|!qt7i7$*mcm`JG3H1?+!r8b&2r}VWO=5|gT8gwd(?kP_U^%j3?>@t9u zKQo>+-sozfUFyK)jHXwysn5@zpXmLW_7>1sf(6Ehpy*);GNjJ5i|?$XmpNEoyf~wc zC_Qs_W@JWXddMspR56Ls9@5ZRzEQ1lto5LaMqBn&xL2R8K~`y-Xqaf`b^Exq|67ob z@$RD8;<#z4-1HgKGE0#6wzJ!-Zgw`QPbaW*)@>;-0dKf>B?K}aP>Q`PyETBjD zT-gDh5PuGAZb~$Jq6CCOTYxLH-MJ@4is1hp_9`aAZGONyBwUmtMIN?A$DezZit)5S z#8&j`BG_t>3;@zJeO+8+serJ?5};Lsyw8Bda`xbtR(}LM2Xt3F>`L5-f21|cLI7jH z6%R9-@i=4Rz8t*%B)-))j-+A+m}371+y*kvPy$>;%Ud%9uo?vFe}XqW0`(^cyqH5M zp>GJr1wm)sN(G@PvS@B2IW*TR@$KuWHN>_8-P|CAR<-L6JpV5K!RyX1U-Q@1{!Ku~5&wi-=AtbLrP8Drs7%1hO{^@)N(8BQ9=QJzr; zE2TtU{E&hlif43-CjsIVeiA54>{EaSFW~q9nx!F&TX!~-!IxFU>2_bMbg8_$gLwll zh?#qnY6olCAyo7lgjB<0%Gynw!l-BtQqcIy7Q+gU?*(^IVPW4Ium&Lsn6hc(@Dbs= z(FfMuK^LP|@9Gj7zltFP2%r-5t}f=?AFS)9#c}M_KliMSFfiPpJ%#~E_nf38CTQJ< zi&t3>)$h5Vytp2!qY#Dh@WM9`iF%$XNEco~1%j8s3&&SS_{wlUlJc1OA26=8mftsd zz+?Tk0t@$mf@kHV%Tw<9;nySwPsg6e%+cV#H^HTf00>f|p+<%&1_x3CW4+ug0^jdD45GNutx44mu}O2a%ZsKN4IX9~4QB*; zgvGxjLs>E`T|P;#(d`f>h&w9xOj78<@oauap?Pi30|#g%mM-fKTOJFa%HK0R-)Zc* zl*+PPQa}{0*%Az)h*L5^Z?s0fLWmN$zM4S3U1)<4)vOR@4inK#U9*Zbcc!<@$Y=4P z8--|8qLQa6?K%2CLuS!~NTcN+3=u{>spJLFb z4&`R@NEpG%_Y~E;=OOhC?UT`#G4AJ-N{-cDp~SuP`TTkS{kkV>+|0itwkAe?lWTAR zRjk)^zkE>;d*7dKMGJFI=+45Biuw1B3mbsVG-s3urP z4$U5SCjCGyG0CZ=xv{6=W_?B7c0#%nQJ*ZhS#dlRgqYnyJ2nwJ8u zwkFLS1P!YQ6&!;)Y`m2o15dDPTS%8NsU&`W79_G=!*`1OP<&CT##60Yd^<- zA#tJ4jF$}n7dr2em-C(~v6a2Rx~Oz>-N%E+$LLjt_0S5_3P@Ez%T#2 zN&ESuX=uqoPXB@9@UkO#W|3)@1lkdpvroxzSdYI}LfD)f1t=U(a^I~2zXP6b2e}&? zM0%FwT;d;;DK`pr5F5{kh&-ob*_PsOpi-DWI+pG6AU!6NL65#^%r;`cNvu09yT0D? zy`d&|*7rm!O*dWK*Jy^M123Kx9Ju~q&ZHxVvt_txzgd`vDvfTeK#?3M<@>8nu-ZR9 zud z@+dhEf$S+Q*hpBRX5&;h5rut75nA8fw1uVkVFIi zTg$${t)StYW1}_Uu)nICOTq9&U&sm?9tFDNGgmqF!!;H+?Vr-aV1y#P$^lzxcYl5&7BX~^^OG4-_^ZjkhdGE_?Ug(Z3 zNO(4zUJ`mTVPo8fuQ$p!j%#|4-;l1IaTb04gx?ImAK@nP`w{KT(ww!^%h8C>shTQ` z5tGRW>@w;hJ+BBs`=U9y$wLz{UVZGKK=a(`HnFJWu_vP8N{J7yIk!4h z`NVgO+TEr>sZ-6I_UZwltu!TNrDETbbaC%9J}YS>N=|jxj#Z&n>oWr?hgCSL*zgbv z;8?5{2x2nbp~ZP>Gr%tDbdJAI&UENc{MfOpjiCC80cnjP(U0L``C*kLP3JF4rgiUo z)I_IutdX#@x^1EMF?IRR#s{O^WxE*?yo%gsh3pbz^vg7*7pD_I0t%EpeEre3#HHA)sr4My z9B*tQGBMSc(L&M^QE{4=jG1en`EOU36U1uBD~kgyBhzbk`kv+Rw27`p=4tKYqQ=^; zQQBC`^yS|M=S=WIZ_l}#CQm-|AM8z5*jE&Cq;Tp}qR@9ylQ15|7-87dZB{~thlA|}>+;vp-0 z!%aM*A7!b4Xv)ROLYG$wpv(T-xE0(15fpuhgFwF$@v-0rC++NrFQteFH!u&DJ@u_e z&HK@2nQbf38N$*K%?y-JA?rR*PIcnOD{vlN8PLZ7g})&wSp)jW0^m5@F>>!z;c?b#Cd3a?+FpSS)bGE`6UhurKA#vMx!;BC-B$oFS{G+DDmw2zo`id^! zl7ImNJZXFHsAMk^q0MOKc!}gtR`@;TzY{)(mOZ+}6H?v<_bzq*m3Qeo2$A^}bzrT_ z$6qx;iMDrwa#{5M^RUD+vH!I^>^4p+6*ft8lJcWGDa>2hn42qo;PVEkcU6w8n`2CX zSWVwXOdLXV=|jZ5^K8k)8ea&aK+u8>wT&bk7f;Tj;V7Grg9EJ2LJu<;$aDJ zk>89Q`)vCg@pyxDG=IaxS~GCog9O$`I~(1uJ$dpjOiyt5@JIBRRS`&T+-I4b?x$Um z<7Uub(D^guBh0OS=$BAD=QViPM^uO9`-7}<;}}$Q1;VoVlci7?97ydwS{U=YBUp@X<|K3(D(sC%ZC0#1_M-?J6o@9P8t~qyZzTDyYj>zHIK*_3>cf*%+5W& zT&!&^Dy`FYi7Ekd3m&znvvd6B#ifdy=y1v7&3n%qcu2>-`^`+$bXho#t(7KhF%2XY zboN?4(cK;X!1#ny_c*TOHbFb-&uw&rAIZyfI3+x7zrzFsNB|d6TNt66+CAqwkeJ3B zVVQzDDRvNFe>6vS@t?7?TD>JPlEWDn97>-~31(ngwU;U0PS?aP@4w->IJL1xvA{yK zQYD<<>8Q+i#_kgXxbXUV{$(U8Y5tbST-ao%PC)lkf9||N?y|#jJ2MY+Q7_|H&-#90 zZTktG%MZA9F=L_>D(ffXbIZ(n72)WITh!Qji9i$o3_)Qj$X)RcFW{jw+A!0elf4 zFo7(R;aPEuui{7%sUS$*N}^T8t6Q1xr`#d7>j@<5!~1f|YZNV{uT2abz-w<=X{dPfEdqUiSG+J>>+7vHJmlY3wnVkmk|h;*=izK%|oJBPd;4fM{X#C%yussp)y{U$$nk5-7uT{H+y-C%`!VWJ)TDu9L#s6grTQIn* zf@!uW!gCyh)`4JIMiNqr{W~}yWti|!WtcQU85Rsvh9$34hMmSM z!~EBjVL00xh#x-!SA%_6wQB#47KICJL2xRF#JrB}0lqWfuhe=9#A0W{((E&a%}TXX zJ3pvUJSS0$`Co3diak+gnL0F$my6N2KBg7>f0h?T?k37gOC^mbaV}yXUVvo^22+pY ze+aY#;>{b_OVZph5|R*U`91n58S&;XDr^rVYytexe>1d$0!ER$X)QMp!yG)x6?@l( zOn9n$=v#6eUImGI_yCBL1;LH~nK)T8ZFdnrKqFoUYVt;kf8sBgAK&%Ya?V$T9$YP;GrvNHiGgI%jlrzQ67iZPg{x$~W z2@cZLunE9kSVD{)%Kwh@1sq${L2EZQXU^7Unf`?#F&pUb!~tf(d+ zS*TyXZSjY#ERmuRV(nHWw$cBJ#5S|@e->Z2!?5_vRjdgDD7v+T2ERhM1fshf`Eu0D zrl%WawM=c2vS|fXFmeI{)^bN`#`{7iqzm5Js_h`nqkI>rTayDwrDjNi z3+W|`%RC+fcE_;T%ZQOj7$jxlgQ7O!ckJ67w)wvu)Zrl{`2fj7YP9P?+R4M{XyS;; zRam=DQVSS3h+ZTswEdUECh>Hr(QrkV_Xx|SjTy7D!0K(U}#6kV`r>v<7K8?i|e^j zwSit1$=9y!li3xpnxuuG&2i*_w05$#zb6>+euzoSdcmOaA&6J$$-WrR?=#oD1_PP} z3tnuD0r?yL{Ii6RzoB50Jmh5F@zco+RjmO|W)ql`Idz?rnKaK3m*kFnl+0ewk2~gu zD$MEMom(8^kz8&GUheu#R1{+PJY>y3JVNLFh&a>GVDFvy#-z%foGJew)e*dm|5WYz zOQ;S~X}-ePp5+x;m*@om5niMs2MlCEiBo<}6AIuM-9IDj{#~dJPZ0eZ;wA}b@fQiZ ze-o<1zniRw^mbUjHbUzratvkFV|e%|L2bECJPFZ@?hcK|=?Lj>)2U&*1jh}e0DlieG3d}=r1twnt z-R{3oU`kipIJb%YRA2@I1?Hud`LUzVLMO4T+h2+Bp;bTGZMa7y|-nU$UI z=Aq7K#3ghnA${cJAF2a+7PBF0R0W08Weh0`KRgind-W~$%HB^e=srn8)#ZCFi$hdh z_X<@<(Bu1`>#9KY5oQSJ(%(k8Zu|4ngST(A#pXzJzAXKUOG#7QvVS->32|sYmzYP905-J(g(C(}RxuzFfEb z+zkOR-K#ZB7f8T#n1!F1j`<|ObhRs(Zg13oi0K|T*k<>CJ)iP}viYYtLd|b(-s^!h z$JXg47R{+EFeL<(11@C}QidZANTq~t30q0iW|r^}$`Qvh?v) z3O}wWU6jeZp8G>`+1n%zoKl7{9DQ2_fD|9q6hX!TM}7gXIzuiTzV{)y4==oLy75s@ z3UJ~5gFGW@1zLQ+2K=z@8`nZ*R>NuVyDRz+a_{sCR%HaA3NaZZl<*@aM*-=Ih>q5Tk*GirZ0jN@ zk^q-iW`LX+kV?mM=(mcBOAiE?Dh^%|F^Jij8 zNVEoRuFyn^cE1m;K}7G=w{3b;4?H{8R><`f6+JNV(D(B0067k}gr6rfXee3|0m{a$ z()2(fkPBqX{312*n}CpIb~LTxYGME?$hQMscv6J=_f?e&-l;VTyekS!+bCQI;K2 zD!SUxg0Kb|AoRP;F40_T9tkhdP0<2OU&N2cAel~6&biej5bgZ<^s@!+4LO>|xU#aR zxdlyk-TUvEhj?Ia6txZ|+i9h0)*)%WwSNYA{ffe@A6vPFT2 zB&{M+G9Wgf{O~s_*f=D((kMwTCbXiZ#*c?cL-zc7qWi>O5Zy9;OgHABTvA%4f`6M! zik_~KBmkHzqF)}Cb~$SipLSWZ5=xPW&y%-y_$U#`2#HiGw~{z~Wwt}}7!77TJS71k zY~C2u09frFsIS2IRK)Hgmy)20Y@P!&{H6p6jv_n&0yt$4fd}BfsKrR4lL3Mm{12)r zvaL&K#)kWYTrdXvuF$$!!;Y$OSeR% zwgX2on(W)>Oo-TSf$f#Csvxw-yf^q;@Af%GX>mSI$K+wI3{(E6)}a=>t%FlO%srM> z#U`IE(RGKy_HWhyRL=j=^W^me?diu+=Dg-D>C|C$!r|PmOQT6Afec`=|FiYj`I1 zSQy>EWVR!pD&@3AVY;Z&6+zt8Y?|etCY4=9A?&EUM+Phv*>$ZBSHyk{Xr(Xr<>gT^ z8=Fg4cdLj9kK@MQyIqkidRm#_CH(413;n2B6l3!I9%Wk0Zi%>p*@0Pfuc-<~KFF}) zE+v4Ni6gl)KIV}g0}LR@ufgz`e9TLwXG241uYMidoQb)sZEoQw7G(r7)8tQlSb94B zh9%*fEz%c-Dtzj<^qM`nU&uok)a>FaqME%}-TH80$Y)6TNnGjJYA;(#%T$Hre=C8^ z7%Io-l|I>3qG5-Ala}H*7U=3vv2gI2%bf51k+unysL4xB0ArSD*Co%}qx=!{8jH8` zlenm|sv6VddmDzG6R)IVY9B6VUJp!d#0ZS+pPwmvZj8B8|uc1TL5?#&7-YtjwxcafZ6v)2;; z=CeT4e*NWl^INsbS-obahN(f*=94^^{Vy$!%j6jjBZo>Yk!e^gv(aR^qXn+x^73fC zao%TC)uPL1l=DmGEXEjxE+!{;LT#%65I_7j;j+td4dAcoJIG$f_1JqqXDlj>|NWTMbKZOOuczPMzMU;hUvBS0 zg$gL=qR?)Zwv4#a!^qm`Wmk%m+tzDiG(WDjnCUfsqu6~^S@I8m70>A;J0zF<>uLUpb62N-1-f@%KY8V3$070~*TZO)^VB? zFs!yx{Io79q$`rqvl{I`F*N>ve@pnEo2U#&^R-B!pHL zk`mBtn(m@VlsM^a=fInEQm=d(=%e7j5p;t8Nw}TU^^=wg$3>uQg(K;E` z_$ddz*PN>~%{(AbwCMS5L=s6ipJLTlyLcgXK>=+Yoe_G;hf&alm(F90vte&JCO8H@eWi_>jAyDYYOt6m?ND-*zo;XG2G+4-{=82Ra z7qPyYFo{`8r0T>gOec4S>eJrm_o_shzPbE7xdk5OVeuI*I2{4{76kN~_`@(L;W02F zqi_rgMrdLUS}M6!xiCii{k5YY0axKD%IwFY z7}8x3DdY!VR3KIc4E7#Or^LD`;B_ea0I)!b%u%G2;aPLEy(CkNs)O{qZ8Ge1t0$VB z+Z=brC^e3{z+|?RQZlk=G#qU@?gXo+$SXK31s77Hb6%bFUKLb;!P6q8`mO*Y7v3=O zk`d)bdhm{abfre_Xfj+O57O4O#6QxgLGzm$hldM#7U)D>%NV^->RPLPPRkW{>iT&N z8$G@}REOe*{`~xig5EBEe=BP<%iO&Jd@K?cR(4^gPu?TB+>37@d!FWL<=9>mlzB3v zk<;?AXEZ!FZ~Si9_~)TulY0looLq6K7s4!4`)pD3?VpDq>CMMjb7L$U?1p$|GHTNj4C4sb?>~VmK#}wt=ntNkh^M4Fy$Un|JmuWLDT-PMQS#eJcXJJ`{uckJ zx0-eX1<9YsoKvQzBQD>h@m<4#0VyN{hnk=_bTP+B@MmuPqnv6D68vc?C1W0(OoBgK zy#vh;S`#SEk8S zpVsX&w~uDDds}a6_snoG=ed4Zdh6^a^!tX^&n8dWQIT>vrwlo~UN>?TytPn^l<$67 z9|rypKHUperu$e$uMq-%C@wE?0ngoe*qbDXM9l~5E&qtGrpRNC*jwZm4`vi!O|t^g zdC_}$uFQ^vdIops zD0*F|gE)S8SUyY65^i(7 zzNW^PwY>RJW14DviuMVZC)qT4+z3l+;*^Z~yKOzxujW7A*5?V^dICCH*-o@(h&6fj zMA9Kd);wgkXuZz?ng?jGr^DR?_}=YeGTLbllLLdT{-Asp(~bpEBlaZP;Rx+ix7>mc zdV1x8VcB77VMd<6pD=KY3V)$*#b@ytyZsWM^GLra|LukrOFm1pb8~m~q6|#mHzrML z|8VKSzSbRTu@tm!cyfPBPO9$kx9>A`dL7P{wfSRH=Xqs!IE$4mXg-zCZNa{*Qhugy zsClh>KU?>NTaLk8phr43xlXu*lcCU{`dIlJJc1MLo{kAhY1s(02?(Q+$4tq)VeJLI&Qy33g9Le72ztpoiN?qqgl$BBR z*cD-=`wBnY`@7=0Rqln02XhHH3Ggw++f@f;e{83TwU~*~clRg~a8BZI{3`hBNwUgP zgmFbf<+nuBal^bR#@3f(jhZnsr#VuppC(*kr zyNhSK)8`DAyLw!3?J=G^X<`JE8zbx3rGW{PPsunX{Z3h#hmIOK1v&Vk@Ni%-4w_(R zo_))&0yvNp|6e%2muI@$)ifdGH@mETFCH)f!{a)B0rvnfbn|rnY4}b_FZOYX0>8oH z;#T??04p7a{4O6x!64IxYHHtr9qcwA#V`a;;U~!epleJqW1Oit;UNNqR^x10SSkzxQYuq`vx|gQlmjfG7i6gq zVZ>+Pw@upy!OoJ4>)!s#VIDkW`FI$fIUEmU5TiRYU^xT`K&B`jo)w^PTPq5H<>?x7 z5PJJnGOw+|Gf3uI70M|xa64I?q+m7y&jKjF4ozYC_r7SCW4Ah5qJ0EA2j5+q|8jTf z7U+GYl_rs~aO2*j^p3~^#T|Ln9)eEkcDZw&7u5?3BBSax=hgTu1fNj%seD2nWfVOj zuQ9YgyuhwyWM)1iXBne5l9(69HG2h#q`=IoN}y@^m-Qr z9vyp1lS9YOTYowq@T)c=VGHQqH=vRMk+A_8i0th2RK$=YjX~3W9dDT%zjT^kBtmsc z>K&yFGo8oUiInO@4MwiEpL^BKh9}ejz5%V_@bL@{J6@4gc;?>R_^&=SwCVyxr3xt$ zETt_=&1i}YZF;6D8!fB zem62=SKJH1f?8gUp<;RoqnE`uv^&z;UJ67V(U>PTcAVE6J04cnj%pc;%0i5Gxn>1Z zjPu%kD&e+sIoWUfq?Pw_pBi$AlwACA=FCzFavs4${W6Sn3%#7fE$9UGJHGhuu^-1o1B;`M5YOquz>za}92*KJwSeCTf|7D@Kt+I(kKmXDawP?$DS$U% z4Zi_bl4ww|&_zi`nC%N0!C3Hf!q_efB;30IdL4;5h9sTrk2cjb??93;*dW*gcG zIp0+h4@W%&6Z&HU+14w@mx$If{Cg{6jlw0?eGSlB)?rzJ@_l9;L?_4$Vc=P zoAY-*A|>62(Ih@1`Jw*dS$*^6n#51CR$Mw`RoKtQkq*7rlYXE5YRkg}KN!7a!BlYpm~ zvw4_^y$wKFEd)Jz!PQ)}a=X0iiEgi@S8dNT98wv=BF$Y}iqp;Oez0n|88*JCjf=4j zGqo1#Onr3HNx-sEzB_jQ3#V3`R_4`z=qp&a$lI?h@-QC@-r3^Fjs(wF+%24|zCZ`%7hRDw_X7&gQ@ z-HOdavy}OI|GfqS|I%j>dRFHe>d!~1T|=iU78W>kQ8Duv7zuL)=`~blw9&mc78FqM zIN0T>du_h)0#!uftI8C<#6}gqYHy}hm(H~f9N3E z5a+p&aCo_^cv8oAt-GML2|VvJo^LK&hue(oH)|<bAZVs8wybk6u#$(`JRYyR#s z`HtxlGCZO}=Y(-nIV^v_mS^b)0wXYZHA*`t1k^mNj-IrNg@kD89XJnE3eNo$})6LE7%k?&2&3dPUvuC;W=K?Jaw8HeBF6w@}BP;c>7rT|2 z*->}XqMwR#gU#Fx&*c;yC;G8J@28)_HB&anC`x*Ct`h2CGVM5O;~xWM*rC$GbB&x~ zdwv6U*0BKB+Z6K$p8~G&j}@*l3lso>xW*`mYYbB-aE&OyHQrp|8hd|ojYmiJ&&`x2 z*aW>TGr)6=T^YvmAoa`zkb1^#ag}TI23+GtGF;;xz%|xDTq7ThYt#W;BhO!Rjl;}F zScq$EUf~+=RyDYMzUy4Pmj`%J#YfJw;J1l@eW8qR6O3Grs{;$OZ!dcp=VQmNIK|`TfNBi6-j}~ZHExa50#u_`uTKo1 z8jr70jT8i`QFx7N>^usn#$78^qbq@G3}^XEs!=dXL%*R99slS|O~24LMnI?%C)dTS3is(@y#tz9$CDjM6LnMof0X}I z(u^EXD^D9qGD|=afmP^e1MHRLH-}Y%i>p~z18woP0Pw?sUwaN;XTf^!&W4=zhArPK z>o`x!53uw4^KT;hj*z+rw7xh4_bYA%?PUoqpAQFyA|F1YE zYt!!#SV%8EjrtpWsG$l23uPv8&plf5?D{;9H!UW~2{mfhUT|`}q{9e5gg;AHkd#0} zRse~*4yr8!o|tq4A$<3-on&5_mXd4IkFM(clV=@ zbGXJ2-g-nCz_fO0Bk{t zd&M0|+XG|}3=oTc@!8u`5JQ9EI_N-jApQR!=w`q_!u5|Jp@E{O!}W0A5D~iGh)00`ZR~tM9N-5)Xj1jesj^ zjDFs?ln=TyJx-zPUXJvzDKPm5#eC}OE#l+?E^vlXg zm&!XS%&~){($aS#7{=>I@2+6BZ4iLNEYcl3BN4xh|Hmqt1A)n+ehVQUzOXW{#c_|$ zRMY;1e5-#RBc(h~>+Y@ceVfE9_8*($zMuy*9DYLzQ4n_#L}0$#hB>wo-nbFpxDDP2 zQJvt@UGUb8suQ~~CdA`|>NLe^8T0$ITdseVrWH}b@CP@aRbD+A17kuO@P~c}i2no> z3=;K296d)m$3<@=M(=Ne6{&@WL*GXFm@@zh!ueI`CU=TICXj8t!UconKn*;|3ZNhp z9GCZ-=F`TU?fT}dZ#Cp2@0xK|v`JD}EH8|^^^y9dA}Z2(+GKB>iDgz@gf=dR4-Bi( zCt_N3m6_)nbPK{>L0Isyoz&k?athca-@P`;r&lI<0X3@V`%Cy?!O*2s*T{qhwL}vp3BCiDZo)f|(5*{HqqdPq$H8;V`j7Zg5`QGZ*BCTdS<$h>Bz|4= zU-@Wfq`C-ZCcQip$Ra z+_zO$_wC4PizCT*qS@?LPq2k|5MU5@Q;=o^=Y%FI_!hq8UKpUh18^H^7XY^b#o`C5 zk90j#U~J*DQlGW7&&Yk@XT`bVK5Ne(X5g{NZ8v*=wlC_H+1RHV$E#FPsjX%$pstBw zE^wbc4pSJ&_&)J6aWQjw;qa02Bv z@>@}>Ozw=wC3X8^p}M59Px+i)g?BZsoFS{YShcEw=?B1kPIX6lDKJP=%=b6!(iAXE zPwKFW71l}X%r)9y6m31AQr_Dj>*m{MXvSci>n<*qJe%w{!x|b_Tch3I9X9tdBQMb7 zA?@uR@YkniczKYMIhCFK-1O;4#PWUWO6pXJ3bCk7S!yNm@1fmw*xyvwA1u z#_GkHu$uDIlwA)pIS@=@S-;&AO79N3mvoQo%2HAGi6^4y@MkuI9m}^%1*Dhla7^47 zZMS^SV}5hru4w6;9GSL}2PGtmd%Cweh3ipZv>Qz`3_Z>!wlmr_NY-6nUVyTVF6}Tk zjO>kh6IHJ@{gehPc{Qi!wJ`;!SjpX}Fvldp4{;4;e;m9$UB=kvlsb?!pVpUJo9^XO zL-R4IPbF|MpU<0e>-gO4j;gwkV^cmZS93&iTMZ<(af;q6 z7JnH}695tTx)q7&=zRc+fmcIH$qWQ5;8M?QANJd^e?<=m0UCVDQS;V#;It&5zLav* zP7hUwkemQn<`(0E=yFKt;3X*~!yb}PX^3}MU52@`cp&$%(6CXWR0Uy-=}AQKv0EEx~w0$TIV640T_5FD=&&>@X3 zTunh}HD2#71L&ztA#x+p#D$7$fL4?utnehH6I8@9&BNg(1%#cPd478Eh)yQ)xY6-E z-)UlCwOc9)!d3q8_yz(>>7rOyXaGWzaqu*yE7#sshCLpkb;^64VGQozKq5mSykC1F z+`Wqb#t5aMbzlNOMj$Q~AIS?b;tI|!`>%z8e8DKaHz2s=O)O0Uj&HOfUc-Bz&)fM`2oM|auWb!~jXjNoVhnn7< zbe!IrPj~ZFU<9AD!5zeL%SODI-x5}9Pvr9vVT+bMa-*7iGoPq{(e*gxO+LwhNo zcBy@`Y>0^6%Z{PG zD65DCsfjXi2jdHm9HThBcaXP2rupMpgKe)=TW?-@(Ei+1g65`q zM^#e0;kVr9bwf@|{D?017gZ$>#(8soq}8eA*t>e^T`g0{etJSBk9Rq|G_ z_wtk!F`7A>+48Bi{>O=k@|=7~dowz|u1ZV}T=V+i`qfrr$kl+Ur#F%Nn|QkM4@}F#6Pkfpl&h(Z?qYPN;?mSB2li$aV`n0o z=_d%rf0H$D2Q*JZib=_lTHp#e8v?Trq2R#5vvy-|SX9smB^U@!E5d_gI0EL}V7ceu zd1WS%o5Uk;d&(ff?kn8ZwLC3T6`Yd{3s2Mp7xDu#^tQ`qzbZr012FS0VN8NG@P$zT@WEg>G&I)1JytkJaID?P75(;Q1Rqcrqv zxq%xo?J4YqV?#i}DxTCaJV|+hj+4*0R1zmDZO)pkSQOXKH6&?YDvPNtc$%Azx~e%Z zoryD#7>zT|d43@sNa_vu5ftx)sFfT$Cq_XI^|m3c&rhFny8)1zzo}B5mRSMQE3_s7P7eTld^Yy|Mn4kJ9COC= zmG*0r(9L(JFq`IxFZ7Ljqr&*^7$$s#WgY64j{UO6pF&`IJbCbUyY{#*#9$f`_lUN- z=ooSTLkw(y@*x!xS{AUnpivHfC86=ox<=F?_Dxj8z!(B&K7dxGWn4uFKcRvh7_&P8 zt$GaZi1{t0ZjcTex@R4_+5>#5JLu>+2*YW$*boSIb=XnxLLs-k+?s1BH^eh%0?vZ5 z{}l^XoAEmsS*`409|vrWs-^hCYhF1eG*wz_WomcRD9Q`z*rOvXB`vA8B@>HV!Uut) zh9HYiUD3%Zkn{GStKAN|{sq`|6VKaC62%*!d}Q2l=oZm*By`7-@#&(e(*ZnK|6qmndip^NV!ieeSg(5q7I>lLhiqc)fY5sF024td zN$+%6=h_1Wuje*eOAdRJ^KMIrQ;V3seDk>3VriQVqDs23)HXZ@b%*M#+H};V+Br0CNK(*_iQAF^>{Z1sl%eRcmzlPQ26xrYIxT|^XCY2 z$a<;7Sqau(_HM-2X>-GTQ+Tfh9%lQ5vf2^#5PpAP#gg?-Z1N`E{ee4X{+Kv;zvsSH zyO|VRex48z{6=xOaq?RVD?t2SHD+)>DdFP7Zs02sJqd7-0*{I)W5&$04&a}9+0a4X~E{hutRhwSObwZM#_Y8Td zp&576rm$D8cBknVKW?>*lA{f?*%DQ7h5ci~vFlH?qty8L(j8mdF`Q^^?wI`7Re^~* zkwN-7#~v44w|p=sTD+M3VJ7A|HbzW5q&~R3Q<+DS9_&!Lh_UC?Bif9u?X!M{)vb|z z?~O%Zy$!)`kkX1odxCi_C0&KPspa&DA=lmlb5FoIjb|Gtr+Y z{u;~87nr428XMC*-z@F6o9%08MtvFAbe6sq=ugPn@116SjpR`%f+kquu!ehHA$D-ZO+yc)1x0ghk3W$ z>DU|@D}gijq!rqqg$gZkZhLR6*_)Qua(T2#PX$3$$P_O7<3~!}zCj*$J4?@I|H*mT zlI-*w^L_?FHE|LT$4usizO8D-fYi@n4^nKzALOvmObHNR3KiE*eX|olVmY-IzT=<9 zFIF_OpEYT^=hYrfqT{{>5o-unHN8O>kies*NiML+cmA(oA#s|I1u zsF7g-ILWlkB|kEQe$f+by`B&GwFGJ;-O?M3OjIILik4hRI$e{3@sEp=rF7jt9XWO(K zCGJ!q;KmU-^O;KnGUz;Q1Ngy80AGN+&xZ&Z;(Pmm4YezTkm&*mx=L1AH15880S|CIvxyVT&075n(j{CR-WQSD)bbax>UjyJ7W{?r8|M@n+Tf?V= zj1B|EQy)!&QlKqZrt0F`z-ApQ zj62YCleLZ17X^<4PQ2NFg0IcR2 z2GS*r6gp&n3CgoqEi+4!BGr>|#t>>=OD zWsdE_U*|>+Jd8l_Pbv-H9K)KTrMN2;6?G{Pk$z~4?}iUtVUV<$(a)i@q5l@8I`if4 zNe_Pn>9L4dfhlrl5ZaW_nkqLj5`#|`@8q!jZ6hdK-73M9fx6Dq7p2PQIE)}`*K5a? zn-X=jP8IU+b0!@4`cPt@ep*FxbaY*=E%1$MZa&6LVMz5K`+F#={yQZ9^)@`dp>^P& zO`~AyoE3uj0{Ody!c~@iRZsXrA)!Rqaiv_=P{x%5SRiAC$Z(81%cKLefGaHg2!ftB z1gvIA?0&>@Gy-i^8m26sa!{eEoSLUc z&#iNN!R!3)v*7?E%}0sP^z^-hU%Q4JlVHo%0kK+iEYWif5z^jG{T2sn@3hf~AjIP6 z3~XfipwRhNhC_B|x%-TI$FfrFVoQru7QX5DS~edymg75eAtc?e#>VF1J4%+HJfELY_Qih90MeKzJf37Wp3 z!ZnK(im?{9iI5QtsqrUH@r+2IS3%8rk|3wcgcf)hbIJp zNo5w~nL&O2Un>RJl3xLJ1+W-LtYA@v9Ougcy|xBei~|?wLIS;1?`~xty+CUApY#Jh zTD<&=4v00LSXEvKPMn=;p(Jsj=jmY;*Ad`7+(y7*{BGI&p)*ht+KMh}$~9XVSeeN@R_2{%PYyc?u(D$Yh3f%U7I!A#2@)$i zJ%g2*F|e{u1Xi|)&t@kBD-+ym>cFJ0vb`j^n7(TMHTyf{9$4#nr7_A-iGAeKV+G$C zQ!(EHQ}J_zsTg-%Z++Y)OPXm4w%InXF+kzmPic1(6aSD5+12fXNgMBvQQf->Uf@kn z595K;F?xFHt?Z}SHxz%u z@o!r{4-c22hhp9|d3Y!EvCtYPKF_|NRIxw8^@n0qVq4KY5vKk`nReTGR%13Q0KS{| zrNnb+Xft$m!>0ffe4(}F2H;1vf*#?{z4hVRhEsv|C8gGMdNppt{Na&NN9nHoM%s)? zG{Anh>kfKHdNCyZ-6M0d`RA#gH+wpZwh_;#%6f87-6))P_-P_OEE6^OL*4$hdvBCp za*@hOSC02)^e44Wv6Vu!;Ir;2hN|`*XX?M!9g$1*-rPXV{4`pHkuJH|G5BYFqC$&i ze%Tqrs>w}sKY5{@RKxg}H6Py?8yneLOgB+)HJ&>~zY=N}b=fR8<1{Wce=;D7`lsn> z+N(ya;!u>`4QTax065=+A#FIr_WzIC@aO;IwBe*ukcJ8hn}HJ3Q0YKf3gGSmYyxOI z7ZET(`*r;;KYV|Kkv#{d{NXKZjQ1x0R0Z~ieV{9Qeu*D~wB8_U=Nd8E+4UTxMQCZo z=z@GA{b~%85)(;oA%J183%(=a5MWA%V|7TI;1cF6(_-GDrvo;ysclW?tOGH$=uI3W z7KTlm#gN-B$_?#(-z1j zB2@$o4SiBseBE(IGAcUtzZDc4$^HF1#5ZdiC(KhlO)!@bW9` z4y%4yHunWc_JA}yq3@?Jb7wFF+b$_cR3$KelI+=j-G+@BKj%;_CWNA{+aT}(AWb2J z0yD81D>1*l%~Ngq+J4F^ySYFQ9s>Zza%?ZVdkmSJgrN}7&iVlKUGTH#58Wg{19&Ac zoN*@=`ypUuwYxVGuy6VYz}~on zLTb*Y%a*L>BBtQp_JyN(gUCgXr$1iYATYl8@6CsP+Si6)QtBYLEh+@D+=QY+5d}vi zp$Y`+q|zq+bQ@ zlq9e4Y;*XQd~8PV==4RKB{K?lzk9T?SDj_!gRWm7HHwOfa_E7oMHP>-qrG4mL#f8| z-o`rgSx41v?xp?sRvF$1@dsaz{Dk=fV;?HB%}umjgu(Z17og2%M=2lqV5eR(1?AKf zgmP-$=f<)yezzZG%;ZNoo{L<{DBopX$}E`y(Lnn>F1>OI1rzP(IYI=KPX0Re)`Fu7 zh}mx{B`!nwl{Kkyw<|Xno!xd0p=Spa{5s0gY37*v9R`T$|36^x!T!!-|0RVF;!LS_ zsoe{t(7S;eZX*kS57z!*xNW2ia4Z_Eu3EHI#AGpjbnar|!q{Z<%*++)$|`6x{s&)E zO1{e9`I=-y1(AZb;WslScr_sHjSlAEe^YZ4CRf3Bvwdve5p_ z4%?rJ@7kxl9p=R#h5tqj0tMsV#vcFxQU0&hAhXG{%&rIS`VYyoHUSY|e14Y$rw9Cg zkQ?Sj)!uvXsQJ=Ro6EBIu!2u^ghuso%I^z2lky@hnoQ-XYJuowt2ui4JVY-?!}RiM zh+Yn3rI*=e>E*9o2o(0uA!d4c7KH`srocO54gt--7%;fjQP;l)PMj)~=n+`^(>)%@ z;n`;7@XC}!upHk0BP54E%8o(^QVo=KhMkPuYvl$Y$V6Umx(ro#k=BrxY`+u{o zs+UPTiuHcl9ptY}JC@S1KW-mY=*56u+SzZc$~AoLt%mZ}mZ#dz`N1CHIjOi2H5!+l z{F(8`s+LJ0#q`Vc+LFo43BebO>egOSEnm>xI%SAF(EQ;FP%3^92!?K*Uw`&c-47*} zN2KSsweRz%9_OwDyR>ewv1yDw<0f)aoKt}9!I9}_pChZ|H+lbFw9d3VbV5Gukk?Md zw6}#SYtMx&(>szy(bf{V{OD<=uU}QqTYC5d^0i9d%OK_FPOSoyNXn&;^tP^wrcc-# zG3ID*wc9(g4By|V4=aC`z)ovR>TslOSt(nG#l84-Yjqb|p_Q6&oxCq&dMwqap~!u| zS)p5!=!b(L6)8!b6mH!wC))epg13sy_Ele&6+=Q613+ScnvGPkF{;+D3nrWq%@U=zRtK(PiX1lj^(3NRhQH#@Tk0e4_J znn#ArL_lRVU$_*^t6l&cEL|gl00);yt3a9@mPwK=d0c`5@ZV(%&k(XeFa!=2S)kr2 z21+j(Rx1-Uh4ZO`pT-V+SO>S-EGxtv-v(SaH4@uy? z$=Lp8bB7IOxuZXZLOT^V-Emak*DQDRTtcG==I)+AfztLr)2?nfqov=RCiUsO_vBbg z$yv<#!RZS&3D2g}%~w5oQ=>Xnb@w7JcPia%&(AH7(s?8BlV^o8d8|%+)g0^ec)77? zN5xxt=Zo@HxG%Kt6{Anmqx;pXq0Z#*d@KonS#IjmT5*@@aD-Z)_$=*s? zZ$5>+NE_%E%%qsp>39T7^aww!+$c-d(V@CJ{7eO#0w9!TXqhF_? z6z{0^RD0v=ru!pfT=p@x=hmjX{MgmKoZI@JdU(sB<2Pe}SJ>>N-hRE5JCsi>WHaSV z>p`5=5~hA-bTsHl88M9W9%fnqiaJFl#R$l_qz&cDt1$LG^s3lW4YnY5es0M%x)Sk6 zRbO*Uf*-QKBdEpKK6(vzYt-*BtCMRdHJjCsb1N{jjrzkix~A%t@NW&0=mee`bZdD;hR-~`_gsuR;s)ofP9U0AR9MyaUyqhe;kt9new zMQg7=w>H)h+ZlX!6e~X(%c{N8~_iIrZ zObyPy>#JRF^+qduOBrHo(Klmyi|0gP9A2|BG{ERe-sG7Kq0E<*{3PK^>2|^cZ8&-H zoYUE-i*HR=ToREXQ6o_pKSdBDZw(q$O7^QP%Trz3K{CeEK))jgLXx8jXssl1 z%7Vd5ACJe-W@&0Z=sq>62?L^{JfLNP9Dc4gjM9X5=AjD->w9QqHQeZbdaAb}o@#g2 zryA@dQUAA3b-8c*C7U*AUu6Hvo)V6!Fs~=HmPy^c0V!UcGI1`36K7+ySsn!VPckhp zG#9J1;}`r4Ftic@>)8y2$>|?KYtuV^{ z^S%q8C)WJIxbL)))5FYM$G3$N_>`h-6@!X%()bB&l&PW0x~?6_ha#5xrkxPr?MnB+ zwJjL!jJjb;na3|TIuKtwO%g1=$;PsvyO(>F`eG^2kAP;# zi<*%Y-^$Ihim*AEw1OcZLq>AXiI@=^l!|sk-`_7@G!rYOrd`wo;j(GxfiK6j{od zUBJrS%CJ8>B=+JbT6K#;(S!cAApuFm5E}c(nCcxxrzb9tR$*~<@?pBZp4o~D^d~Rq zjmAYvuex3ZwAiP{@%9s<5`Uv)Bq{BJ_U9R_q@Rd5B2<#ZcTwJm!dFDB?V1v-M3ru# zlCKvO(R{AtUb52t6n|fBx8HfrVjeB_#GRXq{&0T_K=9PKAXk<3*av#9={&wcOT0F6 z6=p=5V~II2hfBP&>#~Fg;^>stXiFEx49xq#+zoSrp7!Rie7k+HElmWYRIw?9(6L^n zh1j{j&FhDZ^?>>4j}cO4;Yjc3fML#tY)|Uhtf-nQCrfbEp!NK+l2*Ee_4jgbP#^u& z=7I6|*Hr0*`+09TzfOKJKg})>6(Roq^px@`GF1?`tV6IZD#{xpP;y?@6+JH++lTKG zihqv()%zs1_a=ds=9d4)l-}{v;N-iGQ`Gdnp6DGNJNjaNoTF9j8@Tzo$h44G(8=zx zNs-*1?FEX@ZmqaMqSo#`DPp}ZZan6!yXCQ4-*gQv9k5=9P#bM?I?X%!#wW@iOvMFq z?9Osb5{tAm_9p?|GWxT9l5JP&6Q!cyyw@2UdcC|}k8d6QvytX(JaE$Oi-GwwuT;uF zYhg!rgQeyEE90Y|(C%A&0UzF@rrRS%x%K1bMt)7FFhC)`2nv{C_wpqrT?HmILPw+3 z;8cR4eqvmpg*NglNIL0~&OO>GUL?tRklmjdA=%=q*AQyXvt^mas+j}r?sWesEUS4W z0{z$S+gs=crD*AX(-mV+97_WF70gCl8g{BBOXPejn3n(JwbQmhw;XhwU3+MZ>3WGb zh7p*7L=W%W=r)({sT4C>L|9Vc-j+za*#0taVfr?Dv5LfZm8JrTa;uLe14hAKSrzo( z{fH_GLuhf@=p=bXn^(aK;nu9a>$U|u&1n}sarCd{L$opL?Id&~2HqgZCZxzyxX6fr zE zviB9UV^t(6 zJ5iz0%D$qrNwy`@@-@Eyn5kkB&ZVp3_$r@NUxmWdd^OD9#eeDXe`d*%Ii^6iC2Lob zuXmY>KGwlI`N4Ywm9ePfxv5^eDl^kox)%y z2cjz&?Gt+d89A*51Jmg%GE6(I+AUNjg_J1UE*)9s-|nIodQEJZ24@ft|9Z(ix)XyYvfz3Js$}!&0gN->eCHoVu zI4halX^reW8TIGK1GG`l;xe{sT5A-=2}X;r(wC@bhV0t zo1MJX^z=32lhgP8x0&wO$qmeZFLTTb+7bA(ar2wAfE=xDH4#ni+!X;*r-i3Wi{2iZ zoh6Qk#Y!kZb16Y0r!Z8h;&=FsGXG)=T7U01=?0^)Bn9MNiOG`5qRFgeVCaEI-fZfrd=h+qCo@R&Jch|c=%x=E_(&erF<$l7)n*1bU zjvFyoE+E>Z>Eq~_jC*~NyIG-QmvxwP`;WSobd`qQlBZ9V25n?xpcT%Wg5awYaVF2& zifLBzAyJM#n5TA`_o6Pz?Cu`RE22{MkN6aLie}uLM^&I(7FfF1z$lb=v5Z<^@hwKV z&5qnEXE;1J!0Q8x4Hz7`fx@!nh1Sh0ChoH&)Ov)k1xN^MfTrhumk*1GB7?m2_T5cd zf0ap9$bU8HDk!vOk?_8T3*{j6lwa>#VwE#_gR}5+PUaQ-)m9kj_iRA5o>fm{pGl(gN79*J!m?S`B z@RqTTPEfs}-7J~3z{monz6CRc%?#8Dw+|EyhFU>T-XYWfzN4px{x<60O5rSGeq9I7 zzph7SUe|nLDCE;2daxa|gA&K010MXa83|s)gSbfY@Gw#x>q^itH`VYt!E>Zw_4;IM zb-lq)qt&Om{q6k7Z==r|i4uR+@BY3;EzMMFb?Q2f7^9?(4F@GI+1C>_vt4@gJ`?SA zq||mY@Uqk0Zt2Zgk$*IOde&z-H5H}U+o~wjnmr_2ra<{+>tKZMb+tHo5;t~lXi(YGW~HwX-)QI50BjGpO~llQq7dKhzx5wwaeH}{I?EkiW{n{ zRc=&Nu{SDUGcy&cYt@hj9FCxK}zPNOS6>S&EvWReDW|>>Ud3ra8tCc&)A| zOjBKFAuks&$={@k4fqqN-00%KQ(fWYB<_gc*g%B8{^sH9uPImVwoS-+kdT_d5$mfdbNgAQ;SAR5iKnntRYW(oE%I$(0==Tt0v>O{l^Sm#B<1_$& zXnZI`^Y6*CvyKBXS(tSr&Uo}y^5Ng4*<8j(P2!(P#BJJqb2cPn_cENgz&150=c_Dy zSL$UH_HlcPLvXg`$M2|`@AQa3vR^E^so9Q*mDj5U3dj5^GDM3uRW{^( zCflV;7+hR`wP?J7qD0?f6aA|d|Khgx>i-;$U9C{imGuF=bc1?+zt}7g_6bj;VUGfc za>&V)+s|`I0D|T91|MfI6|fd z-_Y+&4gQqbgsz-+2kZy{OB?px<&~wdAfEsn(s(o|D$0uZ1s!Td<9MT4P9Io^RjMit zAu&T`0#KpMsUo;jW)V^8HQsa&6)Uj zVM-1MeJey-fFLHFj|bJ@W2r{5Di||s5uH1pvhL>;AqBZqT%*$6OR!l`MkGkFmQAZp z>~F?gz?Z6odW%gR8V&5@YeK!mfD0+(F7!3~GWVhZ&u}wIvm8u-vx5*I%i!{Pgp|tb z%+4}!`7{DwDv}x~(Rh*}g3)ioY;S$xMW6_Obf5d8F}kdd6&?2Y z6w*s1)bPyDHV_#G5di|xg+59Ztn*3}Z*9nX)HoBvlq9B~9pXGD+>NTnB;b#tLw&@i z4^0LR>+7IXh=iPpRVs``yD)R4IestgBcWR)fVm$)#NZyHue^$xcH*A^WR7*$S;Un} zQLaNCVK2$T?k$d8EFY$!X}1X7!q$@?h6B6#YEVxwI{5o4yS;;IAYLlW@)D8KSGW^i zrl2Ea;%1g9(^hw`RO?Jnrw?ZZ<~4jutErde&1?KraaplD(%xI}GBH?6Td?m*gHOKF zxx~d{I=h829q|Di(}h+XO|O4;l6)R38$Z>5T>R z-ni7D?h^ZR{};zcq(g+jJAA^Z171#xB+0_)WF{`-B)5#mvM& znMUju!2@YRf_>U!pN>rzj6Aemr9bh({6Kdqx z(G>b8l1&ITv3-ahf(tWudm$ot>BBws7+h32|?-T!g`@$?(q28SQCmHokdx$79{wq8dg`UVWU zUclygpC{ibR$M!HD&J!E%QmPMUPnh~2P1r{lyzw)grVIgoQOG0zyh4a?0J_kb35qo zKAC-ocj__R!+Yv_Ex97U_vG>YIY z@g)8Zo&ct{3cRE3;`P*CxJrMVWtKZXX>hyl8Oc+9k?P6>t*$_>w2DueD#EdwoH%V* zN2Lcsy0&>fx7)=)x?+e2tnwr*UT@o?ETDgOsE7Z@<)eNT%yZ(F_m=w#MoAq~mumaZ zb{^v|tOxo9 z3LUWx{N(B8L_20df060q`A3xvZ$YzxqUhHU8SUu5rbq4t>}~>E}SB@{zhzF%h?==Oq6R3o{KU4yq%{mKxE<{pNoWHGEp3miS;sr z$17~l|M1{Sx%gD6(*6K>-;06r2la0rrk1zR#%~_qU+Yv+RNh1$>UE2B-)b*oE9CyQ z#M$KJ5084T3Eo%4l&^}~$2@%m-7lK&t)CdTB_Hei@qD`L<+o>jk5URxPZ)Gm6nPUI zGCtb(yvg`!UPW~_g8fkO%aSHgU;}ks5Wi8URlVbWf7re4Z*7*yhnp&}Unq zL%Y^*Mu66mOYap1f?x@0sNN8=20DS2j1r>T;bSo=yO%Jltk$S@$CPr(g|a}LP$5f3 zcL3o4vE30y9suUdYukUo;ygcb1ktm@X3U-} zN5t+HU^tn8^uFB4YyeAuO!9cZRv#v5j{b0X;dP~l2N8n<0L13%xF?6=Aq&%-mkIvD z4hS*z7Sw`gBI+)RW9m1==mmpmM|;_QJ0y%+@>s|GAdY8BIZzGK)ReJmYW_*{YOwQ< zzwKc@Pd|jF=Fq&RW^z_jGcSc?psAibq1KZk6uD&!QB?5otoD4sLJ+J`omO3qP%iTM z0Abpd(j2akc_}1A8<~1c75agL7tI{LjsV0ccC8a)DAZ$m);ejGBJd!f4b(1eI*gE{ zrGS6-17sNcEE)tuLNg!sO67F|?Q(ZzXVIqF_^)_EKiz&4V8evZ;9A>e*|68MY}m*r z$15-!)*|mH9^>iy)xY!H!I&Il2UK(Qvq5!-yxo@FzRkm5L!y#wFxk%iS*|v#WV2sJ z^$(g4JjD*?d$m?pNpzLIPb)C>PHzY{Huh|(StZ|)waVQQBV?TJ-E}g}<3&+)1<5kD zbJ3E&$ay`$P~5K?zvP zr^f;k!HPY=gTWK`{{|cq9q{*X$W^42L35rP8JginOa_WbG)3e`o(J9Z;eaS+1$9mt zJgbU?tC6IDtTIDF2aqvDheDb`ucLH6=6(VbXD&9MW$z+L3;XW`k!#SwK$iFZ-n0n> z;X-=XIaOpaB(*$un7*I+a~OHJbvKIEn0}PZpSl8A!js^ux!=q=pwq;Dng&= z!cOkum}+I3wPv)0fCGzyDXHi39`vrlyl|({IbbsROu-}NBBtO}==_*-e&n$Aa z^-kvLQS^6n$!8qjoF1Um$Sf7m(>voL zf9?)`CP-TC9Nc97Rk6z`v$>7@%Vp{d{*ce zi+jwZ*WkMekVhGfiywm{q>5RMJ@h06;$Mp9ECnyOBsa18i3?O4^}3ur<5HACNB;4` z(>~L7UG^K+lbcTx-JZMCK4Pu!d;!7BO14(R4(UhfL-OpI`L{AIE0N`}N+MC#;~ow% zB#$BgqSzd4Q$RyV)nt7J5$sNF`>m7g*JO4aofpAS_d{0}?!ruj@H1>9k>(uy&Voj0 z6Xi+mTlh9#r$eW<6>&-7=;}(NedH=)Qov&}`;Eb;#>#6S#EMYf@CY;FmTnNY+*zC5 zTeLB*e8Zc$xaFF+?EX(h6D7h3a*Q+4JxRdv;h(W_xh3VKz9)QGzMk}_Hi1H^seSz+ zAwRDl+|fWyixozrjqQqLU#u&UA29gq<&LyJm3sZCTwnVQ`gQ8=b?tM^9yPRx3&~j9 z`axtB5xetabNS8(J!ugb!jQv6SqSs&wMYXNuIt8pN*-c zR-GN{CCJ8;vXmO9!4X1AH2L?ORSkE|NJShO$ zZiebN{=2RUR~UXgWju7{uUWUxZtNtHzPT7P-c85hYdP9IBbg=_m=gPP%2ZY56AMTk zOd!*w67kCyzHpXK=)S|uFNGNvArhTDL3T86Mymi8ZH{!CT?WBwXbl!N0T%hoaJCZ= zYcF`Vd{i|lyl@`g_=3K$6c=oaB+I~(aEhQmi6kU|?q-@KHH~~*w{ow3af=3S2LyohC6$UykaTyps^l{wGD?~s( z0C!A{awU>VI6n!zG=Ql<`fFgOB548vGfGi3Ta}KJ`EI#yZ+YQCXcM0O((Iw63oI>2 z#1x!iKp3-Uw7`P;VLXt`M?#fgZsXUXcf&CPA$)TMl5zqoC%|Z|L6VeEI6(-%?!BPG zo#abO1173#Vj8!M66=LwTJ|nHHak-RZhgZXOetNjx_^` zBv_eiJopmNJ%^LQpokXsEC*r(O(>;ftw6irH$Q^NyS~kzkRKbzey;?sF2QftxtPyW z2c&%JK58qFdycG-1ROfYUS!4+AobbXF4!lI&}f1GZ$9X=`w3@I%&#}xA;=F5b$FR_ zdv|iw$Q7W(JZj&=vUvF?E1tmDzZKj58=clNNlsm!cwno%dVWdqlAxsqidV}=G}<*I zmnL`l!ww9A6ZSKj8kJL?uY7Pc3(VFW$0~&V1L?0$8Ln)=FI}V z4SOj>V;$96kC5981}?hZVBOMlNBpox`}$>))DJ8c$w0`v>30v3Gms8F9V#2Ixt{85 znKdKI+0Vo3&X9}DgH<`6X0R%UqXYAABq;O4B@r#+n<|ir{!gvO5`-q zU+FPBGYYpvYsuc)?7P;lkcgWGfD%>!mn;IY1BTQMl-o!YF8Mb}Z{CTsrH4HjCQc?D z7=%$wY+^|W0^?Gmw;PwURt~^elPr)TjA`;tF7(fC1&Ya=i0na((we}UC*YOcifmr!S`*JP z!AqG%t@i*pc1T5s8;QUM6T|@?sm6z#kk|o`m(NmJsDJn-{yemZ_7DTvqh%%+14Ylh zWp&>}_$Trn7{Fovx-e#yYArqB>g4%V*%3nzWee=Z+p1-0n2B1>gWVsM4zX`pv!S)# qN(Nt%*IY7g-&Fui1l7ug + + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/EthanolPowerGenerator.png b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/EthanolPowerGenerator.png new file mode 100644 index 0000000000000000000000000000000000000000..76d1aaf546e24de9c06a26965c0edd0530d5c75e GIT binary patch literal 45363 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

n&?ZIV~XJzS=Do)0IG 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 Zv8 + + + + + + + + + + + + + + + diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/RotationAndFlippingTests.sub b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/RotationAndFlippingTests.sub index 0a09be029d8074bc3d4f3ad8b1c1af6f12864f26..7eafd5c1c5bcc44e349a1aa1f7ce44430c4078cb 100644 GIT binary patch literal 13456 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 QDgMv@2L_340fiz107_$lRR910 diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/StatusEffectAndLightTest.xml b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/StatusEffectAndLightTest.xml new file mode 100644 index 000000000..4b58a87c8 --- /dev/null +++ b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/StatusEffectAndLightTest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/filelist.xml b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/filelist.xml index fb1fd016e..be951b04d 100644 --- a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/filelist.xml +++ b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]RotationAndFlippingTests/filelist.xml @@ -1,4 +1,6 @@  - + + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/Events.xml b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/Events.xml new file mode 100644 index 000000000..fecc60223 --- /dev/null +++ b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/Events.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/[DebugOnlyTest]TestPathFinding.sub b/Barotrauma/BarotraumaShared/LocalMods/[DebugOnlyTest]TestPathFinding/[DebugOnlyTest]TestPathFinding.sub new file mode 100644 index 0000000000000000000000000000000000000000..b1620c41984769ed9c3e40653838413b3e4d52f8 GIT binary patch literal 108613 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%0D~hdyW31&a#L+1c<04B4MEA& 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 + + + + + + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/README.txt b/Barotrauma/BarotraumaShared/README.txt deleted file mode 100644 index 6ba44b3f5..000000000 --- a/Barotrauma/BarotraumaShared/README.txt +++ /dev/null @@ -1,38 +0,0 @@ -BAROTRAUMA - -http://www.barotraumagame.com - -© 2017-2024 FakeFish Ltd. All rights reserved. -© 2019-2024 Daedalic Entertainment GmbH. The Daedalic logo is a trademark of Daedalic Entertainment GmbH, Germany. All rights reserved. -Privacy policy: http://privacypolicy.daedalic.com - -See the wiki for more detailed info and instructions: -http://barotraumagame.com/wiki - ------------------------------------------------------------------------- - -Port forwarding: -You may try to forward ports on your router using UPnP (Universal Plug and -Play) port forwarding by selecting "Attempt UPnP port forwarding" in the -"Host Server" menu. - -However, UPnP isn't supported by all routers, so you may need to setup port -forwards manually. The exact steps for forwarding a port depend on your -router's model, but you may be able to find a port forwarding guide for -your particular router/application on portforward.com or by practicing -your google-fu skills. - -These are the values that you should use when forwarding a port to your -Barotrauma server: - -Game port (used to communicate with clients) - Service/Application: barotrauma - External Port: The port you have selected for your server (27015 by default) - Internal Port: The port you have selected for your server (27015 by default) - Protocol: UDP - -Query port (used to communicate with Steam) - Service/Application: barotrauma - External Port: The port you have selected for your server (27016 by default) - Internal Port: The port you have selected for your server (27016 by default) - Protocol: UDP \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/AchievementManager.cs b/Barotrauma/BarotraumaShared/SharedSource/AchievementManager.cs index a4feacedd..2e0365317 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/AchievementManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/AchievementManager.cs @@ -551,9 +551,14 @@ namespace Barotrauma private static void UnlockKillAchievement(Character killer, Character target, Identifier identifier) { - if (killer != null && - target.Params.UnlockKillAchievementForWholeCrew && - GameSession.GetSessionCrewCharacters(CharacterType.Player).Contains(killer)) + bool alwaysUnlockForWholeCrew = false; +#if CLIENT + alwaysUnlockForWholeCrew = GameMain.GameSession?.Campaign is SinglePlayerCampaign; +#endif + + if (killer != null && + (alwaysUnlockForWholeCrew || target.Params.UnlockKillAchievementForWholeCrew) && + GameSession.GetSessionCrewCharacters(CharacterType.Both).Contains(killer)) { UnlockAchievement(identifier, unlockClients: true, characterConditions: c => c != null); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AITarget.cs index 6501c1333..8e005243b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AITarget.cs @@ -49,6 +49,13 @@ namespace Barotrauma } } + + ///

+ /// A multiplier for the sound range for the purposes of displaying the target on sonar. + /// E.g. a value of 10 would mean the sonar can detect the target from x10 further than monsters. + /// + public float SoundRangeOnSonarMultiplier { get; private set; } = 1.0f; + public float SightRange { get { return sightRange; } @@ -206,6 +213,7 @@ namespace Barotrauma MinSoundRange = element.GetAttributeFloat("minsoundrange", 0f); MaxSightRange = element.GetAttributeFloat("maxsightrange", SightRange); MaxSoundRange = element.GetAttributeFloat("maxsoundrange", SoundRange); + SoundRangeOnSonarMultiplier = element.GetAttributeFloat(nameof(SoundRangeOnSonarMultiplier), 1.0f); FadeOutTime = element.GetAttributeFloat("fadeouttime", FadeOutTime); Static = element.GetAttributeBool("static", Static); StaticSight = element.GetAttributeBool("staticsight", StaticSight); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index 49389c008..ce74caefa 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -244,14 +244,39 @@ namespace Barotrauma /// /// The monster won't try to damage these submarines /// - public HashSet UnattackableSubmarines + private readonly HashSet unattackableSubmarines = new HashSet(); + + public void SetUnattackableSubmarines(Submarine submarine, bool includeOwnSub = true, bool includeConnectedSubs = true, bool clearExisting = true) { - get; - private set; - } = new HashSet(); + if (clearExisting) + { + unattackableSubmarines.Clear(); + } + if (submarine != null) + { + AddSubs(submarine); + } + if (includeOwnSub && Character.Submarine is Submarine ownSub && ownSub != submarine) + { + AddSubs(ownSub); + } + + void AddSubs(Submarine sub) + { + unattackableSubmarines.Add(sub); + if (includeConnectedSubs) + { + foreach (Submarine connectedSub in sub.DockedTo) + { + unattackableSubmarines.Add(connectedSub); + } + } + } + } public static bool IsTargetBeingChasedBy(Character target, Character character) => character?.AIController is EnemyAIController enemyAI && enemyAI.SelectedAiTarget?.Entity == target && enemyAI.State is AIState.Attack or AIState.Aggressive; + public bool IsBeingChasedBy(Character c) => IsTargetBeingChasedBy(Character, c); private bool IsBeingChased => IsBeingChasedBy(SelectedAiTarget?.Entity as Character); @@ -539,26 +564,7 @@ namespace Barotrauma //doesn't do anything usually, but events may sometimes change monsters' (or pets' that use enemy AI) teams Character.UpdateTeam(); - bool ignorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f && (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X)); - if (steeringManager == insideSteering) - { - var currPath = PathSteering.CurrentPath; - if (currPath != null && currPath.CurrentNode != null) - { - if (currPath.CurrentNode.SimPosition.Y < Character.AnimController.GetColliderBottom().Y) - { - // Don't allow to jump from too high. - float allowedJumpHeight = Character.AnimController.ImpactTolerance / 2; - float height = Math.Abs(currPath.CurrentNode.SimPosition.Y - Character.SimPosition.Y); - ignorePlatforms = height < allowedJumpHeight; - } - } - if (Character.IsClimbing && PathSteering.IsNextLadderSameAsCurrent) - { - Character.AnimController.TargetMovement = new Vector2(0.0f, Math.Sign(Character.AnimController.TargetMovement.Y)); - } - } - Character.AnimController.IgnorePlatforms = ignorePlatforms; + HandleLaddersAndPlatforms(deltaTime); if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer || Character.Controlled == Character)) @@ -986,6 +992,69 @@ namespace Barotrauma } } + //how often the character can try ragdolling to drop down + private const float MaxDroppingInterval = 5.0f; + + //last time the character tried ragdolling to drop down + private double lastDroppingTime; + + //how long the character can stay ragdolled to drop down + private const float MaxDroppingTime = 1.0f; + + //timer for the duration of the ragdolling + private float droppingTimer; + + private void HandleLaddersAndPlatforms(float deltaTime) + { + bool ignorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f && (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X)); + if (steeringManager == insideSteering) + { + var currPath = PathSteering.CurrentPath; + if (currPath is { CurrentNode: WayPoint currentNode }) + { + Vector2 colliderBottom = Character.AnimController.GetColliderBottom(); + if (Character.Submarine != currentNode.Submarine) + { + colliderBottom = Submarine.GetRelativeSimPosition(colliderBottom, currentNode.Submarine, Character.Submarine); + } + if (currentNode.SimPosition.Y < colliderBottom.Y) + { + // Don't allow to jump from too high. + float allowedJumpHeight = Character.AnimController.ImpactTolerance / 2; + Vector2 diff = currentNode.WorldPosition - Character.WorldPosition; + float height = ConvertUnits.ToSimUnits(Math.Abs(diff.Y)); + ignorePlatforms = height < allowedJumpHeight; + + //trying to head down ladders, but can't climb -> periodically try ragdolling to get down + //(may be required by large monsters like mudraptors to fit through hatches) + if (ignorePlatforms && !Character.CanClimb && PathSteering.IsCurrentNodeLadder && + ConvertUnits.ToSimUnits(Math.Abs(diff.X)) < Character.AnimController.Collider.GetMaxExtent()) + { + if (lastDroppingTime < Timing.TotalTime - MaxDroppingInterval) + { + Character.IsRagdolled = true; + Character.SetInput(InputType.Ragdoll, hit: false, held: true); + droppingTimer += deltaTime; + if (droppingTimer > MaxDroppingTime) + { + lastDroppingTime = Timing.TotalTime; + } + } + else + { + droppingTimer = 0.0f; + } + } + } + } + if (Character.IsClimbing && PathSteering.IsNextLadderSameAsCurrent) + { + Character.AnimController.TargetMovement = new Vector2(0.0f, Math.Sign(Character.AnimController.TargetMovement.Y)); + } + } + Character.AnimController.IgnorePlatforms = ignorePlatforms; + } + #region Idle private void UpdateIdle(float deltaTime, bool followLastTarget = true) @@ -1229,6 +1298,8 @@ namespace Barotrauma return; } + if (Character.IsAttachedToController()) { return; } + attackWorldPos = SelectedAiTarget.WorldPosition; attackSimPos = SelectedAiTarget.SimPosition; @@ -1751,6 +1822,7 @@ namespace Barotrauma { SelectTarget(door.Item.AiTarget, currentTargetMemory.Priority); State = AIState.Attack; + AttackLimb = null; return; } } @@ -1761,12 +1833,20 @@ namespace Barotrauma float margin = AttackLimb != null ? Math.Min(AttackLimb.attack.Range * 0.9f, max) : max; if ((!canAttack || distance > margin) && !IsTryingToSteerThroughGap) { + bool useManualSteering = false; // Steer towards the target if in the same room and swimming // Ruins have walls/pillars inside hulls and therefore we should navigate around them using the path steering. if (Character.CurrentHull != null && Character.Submarine != null && !Character.Submarine.Info.IsRuin && (Character.AnimController.InWater || pursue || !Character.AnimController.CanWalk) && targetCharacter != null && VisibleHulls.Contains(targetCharacter.CurrentHull)) + { + if (CanSeeTarget(targetCharacter)) + { + useManualSteering = true; + } + } + if (useManualSteering) { Vector2 myPos = Character.AnimController.SimplePhysicsEnabled ? Character.SimPosition : steeringLimb.SimPosition; SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - myPos)); @@ -2311,18 +2391,49 @@ namespace Barotrauma { float prio = 1 + limb.attack.Priority; if (Character.AnimController.SimplePhysicsEnabled) { return prio; } - float dist = Vector2.Distance(limb.WorldPosition, attackPos); - float distanceFactor = 1; + float distance = Vector2.Distance(limb.WorldPosition, attackPos); + float maxDistance = Math.Max(limb.attack.Range * 3, 1000); + if (distance > maxDistance) + { + // Far enough to ignore the attack. + return 0; + } + // Not in range, but relatively close. Let's use the distance factor as a multiplier. + float distanceFactor; if (limb.attack.Ranged) { float min = 100; - distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(min, Math.Max(limb.attack.Range / 2, min), dist)); + if (distance < min) + { + // Too close -> smoothly but steeply reduce the preference (and prefer other attacks, like melee instead) + float t = MathUtils.InverseLerp(0, min, distance); + distanceFactor = MathHelper.Lerp(0.01f, 1, t * t); + } + else + { + distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(min, maxDistance, distance)); + } } else { - // The limb is ignored if the target is not close. Prevents character going in reverse if very far away from it. - // We also need a max value that is more than the actual range. - distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, limb.attack.Range * 3, dist)); + if (distance <= limb.attack.Range) + { + // In range. + if (!Character.InWater) + { + // On dry land vertical distance works a bit differently, as we can't necessarily reach the target above/below us. + float verticalDistance = Math.Abs(limb.WorldPosition.Y - attackPos.Y); + if (verticalDistance > limb.attack.DamageRange) + { + // Most likely can't reach. + return 0; + } + } + // Highly prefer attacks which we can use to hit immediately. + return prio * 10; + } + float min = limb.attack.Range; + distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(min, maxDistance, distance)); } return prio * distanceFactor; } @@ -2521,6 +2632,7 @@ namespace Barotrauma { SelectTarget(aiTarget, GetTargetMemory(SelectedAiTarget, addIfNotFound: true).Priority); State = AIState.Attack; + AttackLimb = null; return true; } } @@ -2555,14 +2667,10 @@ namespace Barotrauma return true; } } - if (damageTarget != null) - { - Character.SetInput(item.IsShootable ? InputType.Shoot : InputType.Use, false, true); - item.Use(deltaTime, user: Character); - } + Character.SetInput(item.IsShootable ? InputType.Shoot : InputType.Use, false, true); + item.Use(deltaTime, user: Character); } } - if (damageTarget == null) { return true; } //simulate attack input to get the character to attack client-side Character.SetInput(InputType.Attack, true, true); if (!ActiveAttack.IsRunning) @@ -2609,10 +2717,24 @@ namespace Barotrauma } return true; } + + private const float VisibilityCheckStep = 0.2f; + private double lastVisibilityCheckTime; + private bool canSeeTarget; + /// + /// This method uses and caches the results. + /// + private bool CanSeeTarget(ISpatialEntity target) + { + if (Timing.TotalTime > lastVisibilityCheckTime + VisibilityCheckStep) + { + canSeeTarget = Character.CanSeeTarget(target); + lastVisibilityCheckTime = Timing.TotalTime; + } + return canSeeTarget; + } private float aimTimer; - private float visibilityCheckTimer; - private bool canSeeTarget; private float sinTime; private bool Aim(float deltaTime, ISpatialEntity target, Item weapon) { @@ -2630,13 +2752,7 @@ namespace Barotrauma { Character.CursorPosition -= Character.Submarine.Position; } - visibilityCheckTimer -= deltaTime; - if (visibilityCheckTimer <= 0.0f) - { - canSeeTarget = Character.CanSeeTarget(target); - visibilityCheckTimer = 0.2f; - } - if (!canSeeTarget) + if (!CanSeeTarget(target)) { SetAimTimer(); return false; @@ -2817,7 +2933,10 @@ namespace Barotrauma } } steeringManager.SteeringManual(deltaTime, Vector2.Normalize(limbDiff) * 3); - Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos); + if (Character.AnimController.OnGround || Character.InWater) + { + Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, maxVelocity: 10.0f); + } } } else @@ -2961,7 +3080,7 @@ namespace Barotrauma { if (aiTarget.Entity.Submarine.Info.IsWreck || aiTarget.Entity.Submarine.Info.IsBeacon || - UnattackableSubmarines.Contains(aiTarget.Entity.Submarine)) + unattackableSubmarines.Contains(aiTarget.Entity.Submarine)) { continue; } @@ -3509,13 +3628,16 @@ namespace Barotrauma { if (targetCharacter.Submarine != null) { - // Target is inside -> reduce the priority - valueModifier *= 0.5f; - if (Character.Submarine != null) + if (Character.Submarine != null && !targetCharacter.Submarine.IsConnectedTo(Character.Submarine)) { - // Both inside different submarines -> can ignore safely + // Both inside different, unconnected submarines -> can ignore safely continue; } + else + { + // Target is inside a submarine that we are not -> reduce the priority + valueModifier *= 0.5f; + } } else if (Character.CurrentHull != null) { @@ -4402,6 +4524,7 @@ namespace Barotrauma { SelectTarget(doorAiTarget, CurrentTargetMemory.Priority); State = AIState.Attack; + AttackLimb = null; return false; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs index e84df22f7..320db7e27 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs @@ -1380,7 +1380,7 @@ namespace Barotrauma } else { - isAttackerInfected = attacker.CharacterHealth.GetAfflictionStrengthByType(AfflictionPrefab.AlienInfectedType) > 0; + isAttackerInfected = attacker.CharacterHealth.GetAfflictionStrengthByType(AfflictionPrefab.AlienInfectionType) > 0; // Inform other NPCs if (isAttackerInfected || cumulativeDamage > minorDamageThreshold || totalDamage > minorDamageThreshold) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs index 60ad0799d..5c7447555 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs @@ -4,6 +4,7 @@ using Microsoft.Xna.Framework; using System; using System.Linq; using FarseerPhysics; +using System.Diagnostics; namespace Barotrauma { @@ -50,7 +51,7 @@ namespace Barotrauma } /// - /// Returns true if any node in the path is in stairs + /// Returns true if any node in the path is on stairs /// public bool PathHasStairs => currentPath != null && currentPath.Nodes.Any(n => n.Stairs != null); @@ -285,14 +286,17 @@ namespace Barotrauma } } - Vector2 diff = DiffToCurrentNode(); + Vector2 diff = GetDiffAndAdvance(); if (diff == Vector2.Zero) { return Vector2.Zero; } return Vector2.Normalize(diff) * weight; } protected override Vector2 DoSteeringSeek(Vector2 target, float weight) => CalculateSteeringSeek(target, weight); - - private Vector2 DiffToCurrentNode() + + /// + /// Decides whether and when we should skip to the next node. Returns the difference to the current node (after skipping). + /// + private Vector2 GetDiffAndAdvance() { if (currentPath == null || currentPath.Unreachable) { @@ -320,26 +324,37 @@ namespace Barotrauma Reset(); return Vector2.Zero; } - Vector2 pos = host.WorldPosition; - Vector2 diff = currentPath.CurrentNode.WorldPosition - pos; + WayPoint currentNode = currentPath.CurrentNode; + WayPoint nextNode = currentPath.NextNode; + Vector2 diff = currentNode.WorldPosition - host.WorldPosition; + float horizontalDistance = Math.Abs(diff.X); + float verticalDistance = Math.Abs(diff.Y); bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater; bool canClimb = character.CanClimb; Ladder currentLadder = GetCurrentLadder(); Ladder nextLadder = GetNextLadder(); - var ladders = currentLadder ?? nextLadder; + Ladder ladders = currentLadder ?? nextLadder; bool useLadders = canClimb && ladders != null; var collider = character.AnimController.Collider; - Vector2 colliderSize = collider.GetSize(); + Vector2 colliderSize = ConvertUnits.ToDisplayUnits(collider.GetSize()); + float colliderHeight = colliderSize.Y; + if (character.AnimController.CurrentAnimationParams is FishGroundedParams fishGrounded) + { + // On monsters, the main collider might be rotated, so we need to take that into account here. + float standAngle = fishGrounded.ColliderStandAngleInRadians * character.AnimController.Dir; + Vector2 transformedColliderSize = PhysicsBody.RotateVector(colliderSize, standAngle); + colliderHeight = Math.Abs(transformedColliderSize.Y); + } if (useLadders) { - if (character.IsClimbing && Math.Abs(diff.X) - ConvertUnits.ToDisplayUnits(colliderSize.X) > Math.Abs(diff.Y)) + if (character.IsClimbing && Math.Abs(diff.X) - colliderSize.X > Math.Abs(diff.Y)) { // If the current node is horizontally farther from us than vertically, we don't want to keep climbing the ladders. useLadders = false; } - else if (!character.IsClimbing && currentPath.NextNode != null && nextLadder == null) + else if (!character.IsClimbing && nextNode != null && nextLadder == null) { - Vector2 diffToNextNode = currentPath.NextNode.WorldPosition - pos; + Vector2 diffToNextNode = nextNode.WorldPosition - host.WorldPosition; if (Math.Abs(diffToNextNode.X) > Math.Abs(diffToNextNode.Y)) { // If the next node is horizontally farther from us than vertically, we don't want to start climbing. @@ -356,7 +371,7 @@ namespace Barotrauma { if (currentPath.IsAtEndNode && canClimb && ladders != null) { - // Don't release the ladders when ending a path in ladders. + // Don't release the ladders when ending a path on ladders. useLadders = true; } else @@ -388,20 +403,18 @@ namespace Barotrauma if (currentLadder == null && nextLadder != null && character.SelectedSecondaryItem == nextLadder.Item) { // Climbing a ladder but the path is still on the node next to the ladder -> Skip the node. - NextNode(!doorsChecked); + return NextNode(!doorsChecked); } else { bool nextLadderSameAsCurrent = currentLadder == nextLadder; - float colliderHeight = collider.Height / 2 + collider.Radius; - float heightDiff = currentPath.CurrentNode.SimPosition.Y - collider.SimPosition.Y; - float distanceMargin = ConvertUnits.ToDisplayUnits(colliderSize.X); + float distanceMargin = colliderSize.X; if (currentLadder != null && nextLadder != null) { //climbing ladders -> don't move horizontally diff.X = 0.0f; } - if (Math.Abs(heightDiff) < colliderHeight * 1.25f) + if (verticalDistance < colliderHeight / 2 * 1.25f) { if (nextLadder != null && !nextLadderSameAsCurrent) { @@ -410,7 +423,7 @@ namespace Barotrauma { if (nextLadder.Item.TryInteract(character, forceSelectKey: true)) { - NextNode(!doorsChecked); + return NextNode(!doorsChecked); } } } @@ -432,9 +445,9 @@ namespace Barotrauma } if (isAboveFloor) { - if (Math.Abs(diff.Y) < distanceMargin) + if (verticalDistance < distanceMargin) { - NextNode(!doorsChecked); + return NextNode(!doorsChecked); } else if (!currentPath.IsAtEndNode && (nextLadder == null || (currentLadder != null && Math.Abs(currentLadder.Item.WorldPosition.X - nextLadder.Item.WorldPosition.X) > distanceMargin))) { @@ -443,14 +456,21 @@ namespace Barotrauma } } } - else if (currentLadder != null && currentPath.NextNode != null) + else if (currentLadder != null && nextNode != null) { - if (Math.Sign(currentPath.CurrentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(currentPath.NextNode.WorldPosition.Y - character.WorldPosition.Y)) + if (Math.Sign(currentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(nextNode.WorldPosition.Y - character.WorldPosition.Y)) { //if the current node is below the character and the next one is above (or vice versa) //and both are on ladders, we can skip directly to the next one //e.g. no point in going down to reach the starting point of a path when we could go directly to the one above - NextNode(!doorsChecked); + return NextNode(!doorsChecked); + } + //heading towards a ladder waypoint below the character, but the next waypoint is above it on the same ladder + // -> allow skipping to that waypoint. + // Otherwise the character may get stuck trying to move to a waypoint near the floor at the bottom of the ladder, failing to get close enough because they can't move any lower. + else if (nextLadderSameAsCurrent && diff.Y < 0 && nextNode.WorldPosition.Y > currentNode.WorldPosition.Y) + { + return NextNode(!doorsChecked); } } } @@ -458,21 +478,20 @@ namespace Barotrauma else if (character.AnimController.InWater) { // Swimming - var door = currentPath.CurrentNode.ConnectedDoor; + var door = currentNode.ConnectedDoor; if (door == null || door.CanBeTraversed) { - float margin = MathHelper.Lerp(1, 5, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1)); - float targetDistance = Math.Max(Math.Max(colliderSize.X, colliderSize.Y) / 2 * margin, 0.5f); - float horizontalDistance = Math.Abs(character.WorldPosition.X - currentPath.CurrentNode.WorldPosition.X); - float verticalDistance = Math.Abs(character.WorldPosition.Y - currentPath.CurrentNode.WorldPosition.Y); - if (character.CurrentHull != currentPath.CurrentNode.CurrentHull) + float distanceMultiplier = MathHelper.Lerp(1, 5, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1)); + float targetDistance = Math.Max(Math.Max(colliderSize.X, colliderSize.Y) / 2 * distanceMultiplier, 0.5f); + float modifiedVerticalDist = verticalDistance; + if (character.CurrentHull != currentNode.CurrentHull) { - verticalDistance *= 2; + modifiedVerticalDist *= 2; } - float distance = horizontalDistance + verticalDistance; - if (ConvertUnits.ToSimUnits(distance) < targetDistance) + float distance = horizontalDistance + modifiedVerticalDist; + if (distance < targetDistance) { - NextNode(!doorsChecked); + return NextNode(!doorsChecked); } } } @@ -480,6 +499,10 @@ namespace Barotrauma { // Walking horizontally Vector2 colliderBottom = character.AnimController.GetColliderBottom(); + if (character.Submarine != currentNode.Submarine) + { + colliderBottom = Submarine.GetRelativeSimPosition(colliderBottom, currentNode.Submarine, character.Submarine); + } Vector2 velocity = collider.LinearVelocity; // If the character is very short, it would fail to use the waypoint nodes because they are always too high. // If the character is very thin, it would often fail to reach the waypoints, because the horizontal distance is too small. @@ -487,60 +510,113 @@ namespace Barotrauma float minHeight = 1.6125001f; float minWidth = 0.3225f; // Cannot use the head position, because not all characters have head or it can be below the total height of the character - float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight); - float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X); - bool isTargetTooHigh = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y + characterHeight; - bool isTargetTooLow = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y; - var door = currentPath.CurrentNode.ConnectedDoor; - float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 5, 0, 1)); - float colliderHeight = collider.Height / 2 + collider.Radius; - if (currentPath.CurrentNode.Stairs == null) + float characterHeight = Math.Max(ConvertUnits.ToSimUnits(colliderHeight) + character.AnimController.ColliderHeightFromFloor, minHeight); + bool isTargetTooHigh = currentNode.SimPosition.Y > colliderBottom.Y + characterHeight; + bool isTargetTooLow = currentNode.SimPosition.Y < colliderBottom.Y; + var door = currentNode.ConnectedDoor; + float targetDistanceMultiplier = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 5, 0, 1)); + if (currentNode.Stairs == null) { - float heightDiff = currentPath.CurrentNode.SimPosition.Y - collider.SimPosition.Y; - if (heightDiff < colliderHeight) + // Only attempt dropping if the node is below the collider bottom. + // Using the next node position here, because the current node might be on the top of the ladder, which can be at the same level with the character or even above it. + bool isBelowEnough = (nextNode ?? currentNode).WorldPosition.Y < character.WorldPosition.Y - colliderHeight / 2; + bool drop = false; + if (isBelowEnough) { - // Original comment: - //the waypoint is between the top and bottom of the collider, no need to move vertically. - // Note that the waypoint can be below collider too! This might be incorrect. + if (!canClimb) + { + // Can't climb -> check if we should drop. + Door nextDoor = door ?? nextNode?.ConnectedDoor; + if (nextDoor is Door { IsHorizontal: true, CanBeTraversed: true } openHatch) + { + bool isHatchBelowCharacter = openHatch.LinkedGap.WorldPosition.Y < character.WorldPosition.Y; + if (isHatchBelowCharacter) + { + // Trying to go through an open hatch below us -> drop. + drop = true; + } + } + else if (currentLadder != null && !isTargetTooLow && nextDoor == null) + { + // On ladders -> drop. + drop = true; + } + } + } + if (drop) + { + return NextNode(!doorsChecked); + } + else if (verticalDistance < colliderHeight / 2) + { + // The waypoint is between the top and bottom of the collider, and we don't intend to drop -> no need to move vertically. diff.Y = 0.0f; } } else { - // In stairs - bool isNextNodeInSameStairs = currentPath.NextNode?.Stairs == currentPath.CurrentNode.Stairs; + // On stairs + bool isNextNodeInSameStairs = nextNode?.Stairs == currentNode.Stairs; if (!isNextNodeInSameStairs) { - margin = 1; - if (currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + character.AnimController.ColliderHeightFromFloor * 0.25f) + targetDistanceMultiplier = 1; + if (currentNode.SimPosition.Y < colliderBottom.Y + character.AnimController.ColliderHeightFromFloor * 0.25f) { isTargetTooLow = true; } + Structure nextStairs = nextNode?.Stairs; + if (character.AnimController.Stairs != null && nextStairs != null) + { + //currently on stairs, and the next node is not in the same stairs + // -> we must get off the current stairs first before we can skip to the next node, otherwise the character + // would attempt to get "through the stairs" to the next ones + if (character.AnimController.Stairs.StairDirection == Direction.Right) + { + //the direction in which the bot should keep moving depends on the direction of the stairs and whether we're going up or down + diff = nextStairs.WorldPosition.Y > character.AnimController.Stairs.WorldPosition.Y ? Vector2.UnitX : -Vector2.UnitX; + } + else + { + diff = nextStairs.WorldPosition.Y > character.AnimController.Stairs.WorldPosition.Y ? -Vector2.UnitX : Vector2.UnitX; + } + } } } - float targetDistance = Math.Max(colliderSize.X / 2 * margin, minWidth / 2); - if (horizontalDistance < targetDistance && !isTargetTooHigh && !isTargetTooLow) + // Walking horizontally, check whether we are close enough to the current node. + float targetDistance = Math.Max(colliderSize.X / 2 * targetDistanceMultiplier, ConvertUnits.ToDisplayUnits(minWidth / 2)); + Debug.Assert(targetDistance < 500, "Target distance too large (a character is trying to skip on their path to a waypoint far away), something is probably off here."); + if (!isTargetTooHigh && !isTargetTooLow && horizontalDistance < targetDistance) { - if (door is not { CanBeTraversed: false } && (currentLadder == null || nextLadder == null)) + bool isBlockedByDoor = door is { CanBeTraversed: false }; + // If both the current ladder and the next ladder are not null, we are in the middle of ladders and should let the code above handle advancing the nodes. + // However, if either one is null, and we get here, we are probably walking to or from ladders. + bool notOnLadders = currentLadder == null || nextLadder == null; + if (!isBlockedByDoor && notOnLadders) { - NextNode(!doorsChecked); + return NextNode(!doorsChecked); } } } - if (currentPath.CurrentNode == null) + return ReturnDiff(); + + Vector2 NextNode(bool checkDoors) { - return Vector2.Zero; + if (checkDoors) + { + CheckDoorsInPath(); + } + currentPath.SkipToNextNode(); + return ReturnDiff(); } - return ConvertUnits.ToSimUnits(diff); - } - - private void NextNode(bool checkDoors) - { - if (checkDoors) + + Vector2 ReturnDiff() { - CheckDoorsInPath(); + if (currentPath.CurrentNode == null) + { + return Vector2.Zero; + } + return ConvertUnits.ToSimUnits(diff); } - currentPath.SkipToNextNode(); } public bool CanAccessDoor(Door door, Func buttonFilter = null) @@ -600,8 +676,6 @@ namespace Barotrauma } } - private Vector2 GetColliderSize() => ConvertUnits.ToDisplayUnits(character.AnimController.Collider.GetSize()); - private float GetColliderLength() { Vector2 colliderSize = character.AnimController.Collider.GetSize(); @@ -676,7 +750,7 @@ namespace Barotrauma if (door.LinkedGap.IsHorizontal) { int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X); - float size = character.AnimController.InWater ? colliderLength : GetColliderSize().X; + float size = character.AnimController.InWater ? colliderLength : ConvertUnits.ToDisplayUnits(character.AnimController.Collider.GetSize()).X; shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * dir > -size; } else @@ -794,12 +868,17 @@ namespace Barotrauma if (character == null) { return 0.0f; } float? penalty = GetSingleNodePenalty(nextNode); if (penalty == null) { return null; } + Vector2 nextNodePosition = nextNode.Position; + if (nextNode.Waypoint.Submarine != node.Waypoint.Submarine) + { + nextNodePosition = Submarine.GetRelativeSimPosition(nextNodePosition, node.Waypoint.Submarine, nextNode.Waypoint.Submarine); + } bool nextNodeAboveWaterLevel = nextNode.Waypoint.CurrentHull != null && nextNode.Waypoint.CurrentHull.Surface < nextNode.Waypoint.Position.Y; if (!character.CanClimb && node.Waypoint.Stairs == null && nextNode.Waypoint.Stairs == null) { if (node.Waypoint.Ladders != null && nextNode.Waypoint.Ladders != null && (!nextNode.Waypoint.Ladders.Item.IsInteractable(character) || character.LockHands) || - (nextNode.Position.Y - node.Position.Y > 1.0f && //more than one sim unit to climb up - nextNodeAboveWaterLevel)) //upper node not underwater + (nextNodePosition.Y - node.Position.Y > 1.0f && //more than one sim unit to climb up + nextNodeAboveWaterLevel)) //upper node not underwater { return null; } @@ -830,7 +909,7 @@ namespace Barotrauma } } - float yDist = Math.Abs(node.Position.Y - nextNode.Position.Y); + float yDist = Math.Abs(node.Position.Y - nextNodePosition.Y); if (nextNodeAboveWaterLevel && node.Waypoint.Ladders == null && nextNode.Waypoint.Ladders == null && node.Waypoint.Stairs == null && nextNode.Waypoint.Stairs == null) { penalty += yDist * 10.0f; @@ -898,18 +977,14 @@ namespace Barotrauma //steer away from edges of the hull bool wander = false; bool inWater = character.AnimController.InWater; - Hull currentHull = character.CurrentHull; - // TODO: disabled for now, because seems to cause bots to walk towards walls/doors in some places. In some places it's because how the hulls are defined, but there is probably something else too, is it seems to happen also elsewhere. - // if (!inWater) - // { - // Vector2 colliderBottomPos = ConvertUnits.ToDisplayUnits(character.AnimController.GetColliderBottom()); - // if (Hull.FindHull(colliderBottomPos, guess: currentHull, useWorldCoordinates: false) is Hull lowestHull) - // { - // // Use the hull found at the collider bottom, if found. - // // Makes difference in some rooms that have multiple hulls, of which the lowest hull where the feet are might not be the same as where the center position of the main collider is. - // currentHull = lowestHull; - // } - // } + + //use the hull the legs are in (if one is found), so the character won't walk against the wall when their torso is in a different hull where there'd be room to walk further + //(e.g. if the character is in a shallow pool-type room, like in ResearchModule_01_Colony) + Hull currentHull = + character.AnimController.GetLimb(LimbType.RightLeg)?.Hull ?? + character.AnimController.GetLimb(LimbType.LeftLeg)?.Hull ?? + character.CurrentHull; + if (currentHull != null && !inWater) { float roomWidth = currentHull.Rect.Width; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs index e27bf7a04..664813c08 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjective.cs @@ -103,9 +103,19 @@ namespace Barotrauma } } - // For temporarily forcing walking. Will reset after each priority calculation, so it will need to be kept alive by something. - // The intention of this boolean to allow walking even when the priority is higher than AIObjectiveManager.RunPriority. - public bool ForceWalk { get; set; } + /// + /// For temporarily forcing walking. Will reset after each priority calculation, so it will need to be kept alive by something. + /// The intention of this boolean to allow walking even when the priority is higher than AIObjectiveManager.RunPriority. + /// + public bool ForceWalkTemporarily { get; set; } + + /// + /// Forces the character to walk when executing this objective, even if the priority is above . + /// Unlike , this value is not automatically reset. + /// + public bool ForceWalkPermanently { get; set; } + + public bool ForceWalk => ForceWalkTemporarily || ForceWalkPermanently; public bool IgnoreAtOutpost { get; set; } @@ -313,7 +323,7 @@ namespace Barotrauma /// public float CalculatePriority() { - ForceWalk = false; + ForceWalkTemporarily = false; Priority = GetPriority(); ForceHighestPriority = false; return Priority; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCleanupItems.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCleanupItems.cs index b5304e13c..728645fa6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCleanupItems.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCleanupItems.cs @@ -40,7 +40,7 @@ namespace Barotrauma if (subObjectives.All(so => so.SubObjectives.None())) { // If none of the subobjectives have subobjectives, no valid container was found. Don't allow running. - ForceWalk = true; + ForceWalkTemporarily = true; } return prio; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs index 42e35c1b2..093cf34a2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveCombat.cs @@ -258,13 +258,14 @@ namespace Barotrauma protected override bool CheckObjectiveState() { - if (character.Submarine is { TeamID: CharacterTeamType.FriendlyNPC } && character.Submarine == Enemy.Submarine) + // In a friendly outpost, and the target is still in the outpost + if (character.Submarine is { Info.IsOutpost: true } && character.IsOnFriendlyTeam(character.Submarine.TeamID) && + character.Submarine == Enemy.Submarine) { - // Target still in the outpost + // Outpost guards shouldn't lose the target in friendly outposts, + // However, if we are not a guard, let's ensure that we allow the cooldown. if (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsSecurity) { - // Outpost guards shouldn't lose the target in friendly outposts, - // However, if we are not a guard, let's ensure that we allow the cooldown. allowCooldown = true; } } @@ -286,7 +287,8 @@ namespace Barotrauma { allowCooldown = true; // Target not in the outpost anymore. - if (character.CanSeeTarget(Enemy)) + if (character.Submarine.IsConnectedTo(Enemy.Submarine) && + character.CanSeeTarget(Enemy)) { allowCooldown = false; coolDownTimer = DefaultCoolDown; @@ -389,7 +391,7 @@ namespace Barotrauma HumanAIController.AutoFaceMovement = false; if (!gotoObjective.ShouldRun(true)) { - ForceWalk = true; + ForceWalkTemporarily = true; } } } @@ -468,7 +470,7 @@ namespace Barotrauma isMoving = true; if (!IsEnemyClose(MeleeDistance)) { - ForceWalk = true; + ForceWalkTemporarily = true; } HumanAIController.FaceTarget(Enemy); HumanAIController.AutoFaceMovement = false; @@ -1234,7 +1236,7 @@ namespace Barotrauma } if (isAimBlocked) { - ForceWalk = true; + ForceWalkTemporarily = true; } if (!followTargetObjective.IsCloseEnough) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItem.cs index 2f0f8ec71..c3fd16668 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItem.cs @@ -95,7 +95,11 @@ namespace Barotrauma if (potentialDeconstructor?.InputContainer == null) { continue; } if (!potentialDeconstructor.InputContainer.Inventory.CanBePut(Item)) { continue; } if (!potentialDeconstructor.Item.HasAccess(character)) { continue; } - if (Item.Prefab.DeconstructItems.None(it => it.IsValidDeconstructor(otherItem))) { continue; } + if (Item.Prefab.DeconstructItems.Any() && + Item.Prefab.DeconstructItems.None(it => it.IsValidDeconstructor(otherItem))) + { + continue; + } float distFactor = GetDistanceFactor(Item.WorldPosition, potentialDeconstructor.Item.WorldPosition, factorAtMaxDistance: 0.2f); if (distFactor > bestDistFactor) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItems.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItems.cs index 781ed4746..391bbc4dd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItems.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveDeconstructItems.cs @@ -64,7 +64,11 @@ namespace Barotrauma if (target == null || target.Removed) { return false; } //bots can't handle deconstructing items that require another item to deconstruct, let's not try to do that //in the vanilla game, this means unidentified genetic materials, which we don't want to "deconstruct" anyway - if (target.Prefab.DeconstructItems.All(d => d.RequiredOtherItem.Length > 0)) { return false; } + if (target.Prefab.DeconstructItems.Any() && + target.Prefab.DeconstructItems.All(d => d.RequiredOtherItem.Length > 0)) + { + return false; + } // If the target was selected as a valid target, we'll have to accept it so that the objective can be completed. // The validity changes when a character picks the item up. if (!IsValidTarget(target, character, checkInventory: true)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs index 53ec38880..0a57628a2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs @@ -148,7 +148,7 @@ namespace Barotrauma character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.DisplayName, FormatCapitals.Yes).Value, null, 0, "putoutfire".ToIdentifier(), 10.0f); } // Prevents running into the flames. - objectiveManager.CurrentObjective.ForceWalk = true; + objectiveManager.CurrentObjective.ForceWalkTemporarily = true; } if (moveCloser) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFires.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFires.cs index af532273c..c5790c08d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFires.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveExtinguishFires.cs @@ -11,6 +11,8 @@ namespace Barotrauma public override Identifier Identifier { get; set; } = "extinguish fires".ToIdentifier(); public override bool ForceRun => true; protected override bool AllowInAnySub => true; + // Periodically clear the ignore list so that fires abandoned when fumbling with finding an extinguisher, navigating etc get reconsidered + protected override float IgnoreListClearInterval => 30; public AIObjectiveExtinguishFires(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1) : base(character, objectiveManager, priorityModifier) { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs index 94a876ca7..b2f0ae419 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -49,6 +49,13 @@ namespace Barotrauma public const float DefaultReach = 100; public const float MaxReach = 150; + /// + /// How long it takes for the objective to be abandoned if no suitable item is found. + /// Intended to be an optimization: if the bots are constantly trying to find some item (like a diving suit), + /// it can easily lead to performance issues when e.g. AIObjectiveFindDivingGear constantly starts up new GetItem objectives. + /// + private float abandonDelayIfItemNotFound = 5.0f; + /// /// Is the goal of this objective to get diving gear (i.e. has it been created by )? /// If so, the objective won't attempt to create another objective if the path requires diving gear @@ -213,7 +220,7 @@ namespace Barotrauma { if (isDoneSeeking) { - HandlePotentialItems(); + HandlePotentialItems(deltaTime); } if (objectiveManager.CurrentOrder is not AIObjectiveGoTo) { @@ -389,6 +396,8 @@ namespace Barotrauma // If the root container changes, the item is no longer where it was (taken by someone -> need to find another item) AbortCondition = obj => targetItem == null || (targetItem.GetRootInventoryOwner() is Entity owner && owner != moveToTarget && owner != character), SpeakIfFails = false, + ForceWalkTemporarily = this.ForceWalkTemporarily, + ForceWalkPermanently = this.ForceWalkPermanently, endNodeFilter = CreateEndNodeFilter(moveToTarget) }; }, @@ -598,7 +607,7 @@ namespace Barotrauma } } - private void HandlePotentialItems() + private void HandlePotentialItems(float deltaTime) { Debug.Assert(isDoneSeeking); if (itemCandidates.Any()) @@ -652,10 +661,14 @@ namespace Barotrauma } else { -#if DEBUG - DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}", Color.Yellow); -#endif - Abandon = true; + abandonDelayIfItemNotFound -= deltaTime; + if (abandonDelayIfItemNotFound <= 0.0f) + { + #if DEBUG + DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}", Color.Yellow); + #endif + Abandon = true; + } } } } @@ -718,13 +731,15 @@ namespace Barotrauma private bool CheckItem(Item item) { + bool matchesIdentifiersOrTags = item.HasIdentifierOrTags(IdentifiersOrTags) || (AllowVariants && !item.Prefab.VariantOf.IsEmpty && IdentifiersOrTags.Contains(item.Prefab.VariantOf)); + if (!matchesIdentifiersOrTags) { return false; } if (!item.HasAccess(character)) { return false; } if (ignoredItems.Contains(item)) { return false; }; if (ignoredIdentifiersOrTags != null && item.HasIdentifierOrTags(ignoredIdentifiersOrTags)) { return false; } if (item.Condition < TargetCondition) { return false; } if (ItemFilter != null && !ItemFilter(item)) { return false; } if (RequireNonEmpty && item.Components.Any(i => i.IsEmpty(character))) { return false; } - return item.HasIdentifierOrTags(IdentifiersOrTags) || (AllowVariants && !item.Prefab.VariantOf.IsEmpty && IdentifiersOrTags.Contains(item.Prefab.VariantOf)); + return true; } public override void Reset() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index fd5ade494..79786bcea 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -958,6 +958,7 @@ namespace Barotrauma public bool ShouldRun(bool run) { + if (ForceWalk) { return false; } if (run && objectiveManager.ForcedOrder == this && IsWaitOrder && !character.IsOnPlayerTeam) { // NPCs with a wait order don't run. diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs index efa495d6c..1a2d14048 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -267,7 +267,10 @@ namespace Barotrauma if (node.Waypoint.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(node.Waypoint.CurrentHull)) { return false; } return true; //don't stop at ladders when idling - }, endNodeFilter: node => node.Waypoint.Stairs == null && node.Waypoint.Ladders == null && (!isCurrentHullAllowed || !IsForbidden(node.Waypoint.CurrentHull))); + }, endNodeFilter: node => + node.Waypoint.Stairs == null && node.Waypoint.CurrentHull == currentTarget && node.Waypoint.Ladders == null && + (!isCurrentHullAllowed || !IsForbidden(node.Waypoint.CurrentHull))); + if (path.Unreachable) { //can't go to this room, remove it from the list and try another room diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveInspectNoises.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveInspectNoises.cs index b8639dd08..6439708bc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveInspectNoises.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveInspectNoises.cs @@ -78,9 +78,10 @@ namespace Barotrauma if (item.GetRootInventoryOwner() is Character targetCharacter && AIObjectiveFightIntruders.IsValidTarget(targetCharacter, character, targetCharactersInOtherSubs: false)) { - float dist = character.CurrentHull.GetApproximateDistance(character.Position, targetCharacter.Position, targetCharacter.CurrentHull, aiTarget.SoundRange, distanceMultiplierPerClosedDoor: 2); - if (dist * HumanAIController.Hearing > aiTarget.SoundRange) { continue; } - + float range = aiTarget.SoundRange * HumanAIController.Hearing; + float dist = character.CurrentHull.GetApproximateDistance(character.Position, targetCharacter.Position, targetCharacter.CurrentHull, range, distanceMultiplierPerClosedDoor: 2); + if (dist > range) { continue; } + character.Speak(TextManager.Get("dialogheardenemy").Value, identifier: "heardenemy".ToIdentifier(), minDurationBetweenSimilar: 30.0f); if (inspectNoiseObjective != null && subObjectives.Contains(inspectNoiseObjective)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveLoadItems.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveLoadItems.cs index 894f27e60..65d0e110a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveLoadItems.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveLoadItems.cs @@ -112,7 +112,7 @@ namespace Barotrauma float prio = objectiveManager.GetOrderPriority(this); if (subObjectives.All(so => so.SubObjectives.None() || so.Priority <= 0)) { - ForceWalk = true; + ForceWalkTemporarily = true; } return prio; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs index ad38f8cee..04a9bafa4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveOperateItem.cs @@ -257,6 +257,7 @@ namespace Barotrauma { DialogueIdentifier = AIObjectiveGoTo.DialogCannotReachTarget, TargetName = target.Item.Name, + ForceWalkPermanently = ForceWalk, endNodeFilter = EndNodeFilter ?? AIObjectiveGetItem.CreateEndNodeFilter(target.Item) }, onAbandon: () => Abandon = true, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectivePumpWater.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectivePumpWater.cs index 6c1a7a37b..7aa3d1e87 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectivePumpWater.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectivePumpWater.cs @@ -29,7 +29,7 @@ namespace Barotrauma { if (pump?.Item == null || pump.Item.Removed) { return false; } if (pump.Item.IgnoreByAI(character)) { return false; } - if (!pump.Item.IsInteractable(character)) { return false; } + if (!pump.Item.IsInteractable(character) || !pump.CanBeSelected) { return false; } if (pump.IsAutoControlled) { return false; } if (pump.Item.ConditionPercentage <= 0) { return false; } if (pump.Item.CurrentHull == null) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs index 42cbd4de6..8963eeb34 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs @@ -136,7 +136,7 @@ namespace Barotrauma public static bool IsValidTarget(Character target, Character character, out bool ignoredAsMinorWounds) { ignoredAsMinorWounds = false; - if (target == null || target.IsDead || target.Removed) { return false; } + if (target == null || target.IsDead || target.Removed || target.InvisibleTimer > 0.0f) { return false; } if (target.IsInstigator) { return false; } if (target.IsPet) { return false; } if (!HumanAIController.IsFriendly(character, target, onlySameTeam: true)) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AICharacter.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AICharacter.cs index 879c4197f..669bc3a0a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AICharacter.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AICharacter.cs @@ -42,7 +42,9 @@ namespace Barotrauma { enemyAi.PetBehavior?.Update(deltaTime); } - if (IsDead || IsUnconscious || Stun > 0.0f || IsIncapacitated) + if (IsDead || IsUnconscious || IsIncapacitated || + //only check "real" stuns here, ignoring ragdolling, so the AI can run and decide whether to ragdoll or unragdoll + CharacterHealth.Stun > 0.0f) { //don't enable simple physics on dead/incapacitated characters //the ragdoll controls the movement of incapacitated characters instead of the collider, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs index 316d3db5d..db9322c49 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs @@ -685,7 +685,7 @@ namespace Barotrauma { movement = MathUtils.SmoothStep(movement, TargetMovement, 0.2f); - if (Collider.BodyType == BodyType.Dynamic) + if (Collider.BodyType == BodyType.Dynamic && onGround) { Collider.LinearVelocity = new Vector2( movement.X, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index ed100e587..8f8a4f87b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -30,6 +30,7 @@ namespace Barotrauma { public Fixture F1, F2; public Vector2 LocalNormal; + public Vector2 WorldNormal; public Vector2 Velocity; public Vector2 ImpactPos; @@ -39,7 +40,7 @@ namespace Barotrauma F2 = f2; Velocity = velocity; LocalNormal = contact.Manifold.LocalNormal; - contact.GetWorldManifold(out _, out FarseerPhysics.Common.FixedArray2 points); + contact.GetWorldManifold(out WorldNormal, out FarseerPhysics.Common.FixedArray2 points); ImpactPos = points[0]; } } @@ -826,7 +827,7 @@ namespace Barotrauma return true; } - private void ApplyImpact(Fixture f1, Fixture f2, Vector2 localNormal, Vector2 impactPos, Vector2 velocity) + private void ApplyImpact(Fixture f1, Fixture f2, Vector2 worldNormal, Vector2 impactPos, Vector2 velocity) { if (character.DisableImpactDamageTimer > 0.0f) { return; } @@ -838,7 +839,7 @@ namespace Barotrauma return; } - Vector2 normal = localNormal; + Vector2 normal = worldNormal; float impact = Vector2.Dot(velocity, -normal); if (f1.Body == Collider.FarseerBody || !Collider.Enabled) { @@ -1069,9 +1070,12 @@ namespace Barotrauma } Hull newHull = Hull.FindHull(findPos, currentHull); - if (setInWater && newHull == null) + if (setInWater) { - inWater = true; + if (newHull == null || findPos.Y < newHull.WorldSurface) + { + inWater = true; + } } if (newHull == currentHull) { return; } @@ -1114,7 +1118,10 @@ namespace Barotrauma { //don't teleport out yet if the character is going through a gap if (Gap.FindAdjacent(Gap.GapList.Where(g => g.Submarine == currentHull.Submarine), findPos, 150.0f, allowRoomToRoom: true) != null) { return; } - if (Limbs.Any(l => Gap.FindAdjacent(currentHull.ConnectedGaps, l.WorldPosition, ConvertUnits.ToDisplayUnits(l.body.GetSize().Combine()), allowRoomToRoom: true) != null)) { return; } + if (Limbs.Any(l => !l.IsSevered && Gap.FindAdjacent(currentHull.ConnectedGaps, l.WorldPosition, ConvertUnits.ToDisplayUnits(l.body.GetSize().Combine()), allowRoomToRoom: true) != null)) + { + return; + } character.MemLocalState?.Clear(); Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position), currentHull.Submarine.Velocity); } @@ -1246,6 +1253,9 @@ namespace Barotrauma private float BodyInRestDelay = 1.0f; + /// + /// Controls the sleeping state of this character + /// public bool BodyInRest { get { return bodyInRestTimer > BodyInRestDelay; } @@ -1269,7 +1279,7 @@ namespace Barotrauma while (impactQueue.Count > 0) { var impact = impactQueue.Dequeue(); - ApplyImpact(impact.F1, impact.F2, impact.LocalNormal, impact.ImpactPos, impact.Velocity); + ApplyImpact(impact.F1, impact.F2, impact.WorldNormal, impact.ImpactPos, impact.Velocity); } CheckValidity(); @@ -1312,9 +1322,18 @@ namespace Barotrauma } float MaxVel = NetConfig.MaxPhysicsBodyVelocity; - Collider.LinearVelocity = new Vector2( - NetConfig.Quantize(Collider.LinearVelocity.X, -MaxVel, MaxVel, 12), - NetConfig.Quantize(Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12)); + if (GameMain.NetworkMember != null) + { + Collider.LinearVelocity = new Vector2( + NetConfig.Quantize(Collider.LinearVelocity.X, -MaxVel, MaxVel, 12), + NetConfig.Quantize(Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12)); + } + else + { + Collider.LinearVelocity = new Vector2( + MathHelper.Clamp(Collider.LinearVelocity.X, -MaxVel, MaxVel), + MathHelper.Clamp(Collider.LinearVelocity.Y, -MaxVel, MaxVel)); + } if (forceStanding) { @@ -1368,9 +1387,19 @@ namespace Barotrauma UpdateHullFlowForces(deltaTime); - if (currentHull == null || + bool applyWaterForces = + currentHull == null || currentHull.WaterVolume > currentHull.Volume * 0.95f || - ConvertUnits.ToSimUnits(currentHull.Surface) > Collider.SimPosition.Y) + ConvertUnits.ToSimUnits(currentHull.Surface) > Collider.SimPosition.Y; +#if CLIENT + if (Screen.Selected is CharacterEditor.CharacterEditorScreen && + this is AnimController animController) + { + applyWaterForces = animController.CurrentAnimationParams is SwimParams; + } +#endif + + if (applyWaterForces) { Collider.ApplyWaterForces(); } @@ -1460,10 +1489,10 @@ namespace Barotrauma else { // Falling -> ragdoll briefly if we are not moving at all, because we are probably stuck. - if (Collider.LinearVelocity == Vector2.Zero && !character.IsRemotePlayer) + if (Collider.LinearVelocity == Vector2.Zero && GameMain.NetworkMember is not { IsClient: true }) { character.IsRagdolled = true; - if (character.IsBot) + if (!character.IsPlayer) { // Seems to work without this on player controlled characters -> not sure if we should call it always or just for the bots. character.SetInput(InputType.Ragdoll, hit: false, held: true); @@ -1823,7 +1852,13 @@ namespace Barotrauma { floorFixture = standOnFloorFixture; standOnFloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * standOnFloorFraction; - if (rayStart.Y - standOnFloorY < Collider.Height * 0.5f + Collider.Radius + ColliderHeightFromFloor * 1.2f) + + //allow the floor to be just a bit below the bottom of the collider for the character to be "on ground" + //there is some inaccuracy in the physics simulation (and floats), the collider isn't usually precisely ColliderHeightFromFloor above the floor + const float Tolerance = 0.1f; + float standHeight = Collider.Height * 0.5f + Collider.Radius + ColliderHeightFromFloor; + + if (rayStart.Y - standOnFloorY <= standHeight + Tolerance) { onGround = true; if (standOnFloorFixture.CollisionCategories == Physics.CollisionStairs) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 6fcd7a33b..8201439ba 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -187,6 +187,11 @@ namespace Barotrauma set => Params.Health.DoesBleed = value; } + /// + /// Can this character be contained inside a controller? + /// + public bool IsContainable { get; set; } + public readonly Dictionary Properties; public Dictionary SerializableProperties { @@ -683,6 +688,11 @@ namespace Barotrauma get { return AnimController.Mass; } } + /// + /// The position the character was at when we previously set the transforms of the items in the character's inventory. + /// + private Vector2 lastInventoryItemSetTransformPosition; + public CharacterInventory Inventory { get; private set; } /// @@ -788,7 +798,24 @@ namespace Barotrauma set { if (value == selectedCharacter) { return; } - if (selectedCharacter != null) { selectedCharacter.selectedBy = null; } + //deselect the currently selected character + if (selectedCharacter != null) + { + selectedCharacter.selectedBy = null; + //check if some other character has selected the currently selected character too, + //and set selectedBy to that other character (otherwise the currently selected character would be unaware they're still being dragged by someone) + foreach (var otherCharacter in CharacterList) + { + if (otherCharacter != this && otherCharacter.selectedCharacter == selectedCharacter) + { + selectedCharacter.selectedBy = otherCharacter; + break; + } + } + } + + CharacterHUD.RecreateHudTextsIfControlling(this); + selectedCharacter = value; if (selectedCharacter != null) { selectedCharacter.selectedBy = this; } #if CLIENT @@ -1642,8 +1669,10 @@ namespace Barotrauma AnimController.FindHull(setInWater: true); if (AnimController.CurrentHull != null) { Submarine = AnimController.CurrentHull.Submarine; } + IsContainable = prefab.ConfigElement.GetAttributeBool(nameof(IsContainable), def: Mass <= 30.0f); + CharacterList.Add(this); - + Enabled = GameMain.NetworkMember == null; if (info != null) @@ -2268,6 +2297,12 @@ namespace Barotrauma } } + // Try to detach from the controller if we are currently attached to something that is dangerous for our character + if (aiControlled && Stun <= 0f && !IsKnockedDownOrRagdolled && !LockHands && ShouldAvoidStayingAttachedToController()) + { + SelectedItem = null; + } + if (GameMain.NetworkMember != null) { if (GameMain.NetworkMember.IsServer) @@ -2316,7 +2351,7 @@ namespace Barotrauma { attackCoolDown -= deltaTime; } - else if (IsKeyDown(InputType.Attack)) + else if (IsKeyDown(InputType.Attack) && !IsAttachedToController()) { //normally the attack target, where to aim the attack and such is handled by EnemyAIController, //but in the case of player-controlled monsters, we handle it here @@ -2843,14 +2878,14 @@ namespace Barotrauma #if CLIENT if (Screen.Selected == GameMain.SubEditorScreen) { hidden = false; } #endif - if (!CanInteract || hidden || !item.IsInteractable(this)) { return false; } - Controller controller = item.GetComponent(); if (controller != null && IsAnySelectedItem(item) && controller.IsAttachedUser(this)) { return true; } + if (!CanInteract || hidden || !item.IsInteractable(this)) { return false; } + if (item.ParentInventory != null) { return CanAccessInventory(item.ParentInventory); @@ -2972,7 +3007,9 @@ namespace Barotrauma } } - if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger) + //note that the distance to item should be set to 0 above if the character is within the item's bounding box + bool closeEnoughToIgnoreVisibilityCheck = distanceToItem <= 0.1f; + if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger && !closeEnoughToIgnoreVisibilityCheck) { var body = Submarine.CheckVisibility(SimPosition, itemPosition, ignoreLevel: true); bool itemCenterVisible = CheckBody(body, item); @@ -3001,7 +3038,6 @@ namespace Barotrauma { return itemCenterVisible; } - } return true; @@ -3091,7 +3127,11 @@ namespace Barotrauma if (!CanInteract) { - SelectedItem = SelectedSecondaryItem = null; + if (!IsAttachedToController()) + { + SelectedItem = null; + } + SelectedSecondaryItem = null; focusedItem = null; if (!AllowInput) { @@ -3110,8 +3150,16 @@ namespace Barotrauma { if (!PlayerInput.PrimaryMouseButtonHeld() || Barotrauma.Inventory.DraggingItemToWorld) { - FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null; - if (FocusedCharacter != null && !CanSeeTarget(FocusedCharacter)) { FocusedCharacter = null; } + //don't allow focusing on anyone when the health window is open (avoids accidentally selecting someone when closing the window) + if (CharacterHealth.OpenHealthWindow != null) + { + FocusedCharacter = null; + } + else + { + FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null; + if (FocusedCharacter != null && !CanSeeTarget(FocusedCharacter)) { FocusedCharacter = null; } + } float aimAssist = GameSettings.CurrentConfig.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f); if (HeldItems.Any(it => it?.GetComponent()?.IsActive ?? false)) { @@ -3435,7 +3483,7 @@ namespace Barotrauma obstructVisionAmount = Math.Max(obstructVisionAmount - deltaTime, 0.0f); - if (Inventory != null) + if (Inventory != null && Vector2.DistanceSquared(lastInventoryItemSetTransformPosition, Position) > 0.1f) { //do not check for duplicates: this is code is called very frequently, and duplicates don't matter here, //so it's better just to avoid the relatively expensive duplicate check @@ -3444,6 +3492,7 @@ namespace Barotrauma if (item.body == null || item.body.Enabled) { continue; } item.SetTransform(SimPosition, 0.0f, forceSubmarine: Submarine); } + lastInventoryItemSetTransformPosition = Position; } HideFace = false; @@ -3570,7 +3619,7 @@ namespace Barotrauma { wasRagdolled = IsRagdolled; IsRagdolled = IsKeyDown(InputType.Ragdoll); - if (IsRagdolled && IsBot && GameMain.NetworkMember is not { IsClient: true }) + if (IsRagdolled && !IsPlayer && GameMain.NetworkMember is not { IsClient: true }) { ClearInput(InputType.Ragdoll); } @@ -3622,7 +3671,19 @@ namespace Barotrauma AnimController.IgnorePlatforms = true; } AnimController.ResetPullJoints(); - SelectedItem = SelectedSecondaryItem = null; + + // Prevent us from detaching from the controller if we are attached to it OR detach if we + // manually ragdoll, in this case it should be similar to us deselecting the controller + if (!IsAttachedToController() || + (IsKeyDown(InputType.Ragdoll) + // Let only the server do this check since the Ragdoll input for other clients is set to be held + // for stunned characters even if a character isn't manually ragdolling + && (GameMain.NetworkMember == null || GameMain.NetworkMember is { IsServer: true } ))) + { + SelectedItem = null; + } + + SelectedSecondaryItem = null; SelectedCharacter = null; return; } @@ -3651,6 +3712,13 @@ namespace Barotrauma bool MustDeselect(Item item) { if (item == null) { return false; } + + // Prevent creatures from deselecting the controller if they are attached to it + if (IsAIControlled && !CanInteract && IsAttachedToController()) + { + return false; + } + if (!CanInteractWith(item)) { return true; } bool hasSelectableComponent = false; foreach (var component in item.Components) @@ -4376,6 +4444,41 @@ namespace Barotrauma } } + public void ForceSay(LocalizedString messageToSay, bool sayInRadio, bool removeQuotes = false, float delay = 0.0f) + { + if (messageToSay.IsNullOrEmpty() || SpeechImpediment >= 100.0f || IsDead) + { + return; + } + + if (removeQuotes) + { + messageToSay = new TrimLString(messageToSay, + TrimLString.Mode.Both, ['"', '”', '“', ' ']); + } + + ChatMessageType messageType = ChatMessageType.Default; + bool canUseRadio = ChatMessage.CanUseRadio(this, out WifiComponent radio); + if (canUseRadio && sayInRadio) + { + messageType = ChatMessageType.Radio; + } + + CoroutineManager.Invoke(() => + { +#if SERVER + GameMain.Server?.SendChatMessage(messageToSay.Value, messageType, senderClient: null, this); +#elif CLIENT + // no need to create the message when playing as a client, the server will send it to us + if (GameMain.Client == null) + { + AIChatMessage message = new AIChatMessage(messageToSay.Value, messageType); + SendSinglePlayerMessage(message, canUseRadio, radio); + } +#endif + }, delay); + } + public void SetAllDamage(float damageAmount, float bleedingDamageAmount, float burnDamageAmount) { CharacterHealth.SetAllDamage(damageAmount, bleedingDamageAmount, burnDamageAmount); @@ -4760,6 +4863,10 @@ namespace Barotrauma { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && !isNetworkMessage) { return; } if (Screen.Selected != GameMain.GameScreen) { return; } + //don't allow stunning for less than one frame + //fixes monsters/enemies that take some minuscule amount of stun from a weapon still being noticeable affected by the stun, + //because even a one-frame stun briefly disables the animations and makes the character stop + if (newStun < Timing.Step && Stun <= 0.0f) { return; } if (GodMode) { CharacterHealth.Stun = 0; @@ -4787,7 +4894,12 @@ namespace Barotrauma CharacterHealth.Stun = newStun; if (newStun > 0.0f) { - SelectedItem = SelectedSecondaryItem = null; + if (!IsAttachedToController()) + { + SelectedItem = null; + } + + SelectedSecondaryItem = null; if (SelectedCharacter != null) { DeselectCharacter(); } } HealthUpdateInterval = 0.0f; @@ -4976,6 +5088,37 @@ namespace Barotrauma } } + public bool IsAttachedToController() + { + if (SelectedItem == null) { return false; } + + var controller = SelectedItem.GetComponent(); + if (controller == null) { return false; } + + return controller.IsAttachedUser(this); + } + + public bool ShouldAvoidStayingAttachedToController() + { + if (!IsAttachedToController()) { return false; } + + var deconstructor = SelectedItem.GetComponent(); + if (deconstructor != null) + { + return true; + } + + // Character is being carried by an enemy! + if (IsHuman && + SelectedItem.GetRootInventoryOwner() is Character carryingCharacter && + TeamID != carryingCharacter.TeamID) + { + return true; + } + + return false; + } + public void Kill(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool isNetworkMessage = false, bool log = true) { if (IsDead || CharacterHealth.Unkillable || GodMode || Removed) { return; } @@ -5113,7 +5256,7 @@ namespace Barotrauma AnimController.movement = Vector2.Zero; AnimController.TargetMovement = Vector2.Zero; - if (!LockHands) + if (!LockHands && causeOfDeath != CauseOfDeathType.Disconnected) { foreach (Item heldItem in HeldItems.ToList()) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs index 93e4b1bf6..68110740b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterPrefab.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Xml.Linq; using Microsoft.Xna.Framework; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs index cb36b1196..8008179fb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs @@ -629,7 +629,7 @@ namespace Barotrauma public static readonly Identifier StunType = "stun".ToIdentifier(); public static readonly Identifier EMPType = "emp".ToIdentifier(); public static readonly Identifier SpaceHerpesType = "spaceherpes".ToIdentifier(); - public static readonly Identifier AlienInfectedType = "alieninfected".ToIdentifier(); + public static readonly Identifier AlienInfectionType = "alieninfection".ToIdentifier(); public static readonly Identifier InvertControlsType = "invertcontrols".ToIdentifier(); public static readonly Identifier DisguisedAsHuskType = "disguiseashusk".ToIdentifier(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index f72b31c43..ed5415fe6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -827,9 +827,21 @@ namespace Barotrauma } } + float modifiedStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab, limbType)); + if (newAffliction.Prefab.AfflictionType == AfflictionPrefab.StunType) + { + //don't allow stunning for less than one frame + //fixes monsters/enemies that take some minuscule amount of stun from a weapon still being noticeable affected by the stun, + //because even a one-frame stun briefly disables the animations and makes the character stop + if (modifiedStrength < Timing.Step && Stun <= 0.0f) + { + return; + } + } + if (existingAffliction != null) { - float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(existingAffliction.Prefab, limbType)); + float newStrength = modifiedStrength; if (allowStacking) { // Add the existing strength @@ -851,7 +863,7 @@ namespace Barotrauma //create a new instance of the affliction to make sure we don't use the same instance for multiple characters //or modify the affliction instance of an Attack or a StatusEffect var copyAffliction = newAffliction.Prefab.Instantiate( - Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab, limbType))), + Math.Min(newAffliction.Prefab.MaxStrength, modifiedStrength), newAffliction.Source); afflictions.Add(copyAffliction, limbHealth); AchievementManager.OnAfflictionReceived(copyAffliction, Character); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/HumanPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/HumanPrefab.cs index 67b0141e4..a8ce33b63 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/HumanPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/HumanPrefab.cs @@ -190,7 +190,7 @@ namespace Barotrauma idleObjective.PreferredOutpostModuleTypes.Add(moduleType); } } - humanAI.ReportRange = Hearing; + humanAI.Hearing = Hearing; humanAI.ReportRange = ReportRange; humanAI.FindWeaponsRange = FindWeaponsRange; humanAI.AimSpeed = AimSpeed; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs index d9226ce75..e9f1d2f0a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs @@ -1293,7 +1293,7 @@ namespace Barotrauma if (!statusEffects.TryGetValue(actionType, out var statusEffectList)) { return; } foreach (StatusEffect statusEffect in statusEffectList) { - if (statusEffect.ShouldWaitForInterval(character, deltaTime)) { return; } + if (statusEffect.ShouldWaitForInterval(character, deltaTime)) { continue; } statusEffect.sourceBody = body; if (statusEffect.type == ActionType.OnDamaged) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 14c8e83c8..675faa777 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -728,7 +728,9 @@ namespace Barotrauma [Serialize(true, IsPropertySaveable.Yes, description: "Should the character target or ignore walls when it's outside the submarine."), Editable] public bool TargetOuterWalls { get; private set; } - [Serialize(false, IsPropertySaveable.Yes, description: "If enabled, the character chooses randomly from the available attacks. The priority is used as a weight for weighted random."), Editable] + [Serialize(false, IsPropertySaveable.Yes, description: "If disabled (default), the character selects the limb based on a formula where the parameters are a) the priority of the attack b) the distance to the target, and c) the range of the attack" + + "If enabled, the character chooses randomly from the available attacks. The priority is used as a weight for weighted random. The distance to the target is in this case ignored." + ), Editable] public bool RandomAttack { get; private set; } [Serialize(false, IsPropertySaveable.Yes, description:"Does the creature know how to open doors (still requires a proper ID card). Humans can always open doors (They don't use this AI definition)."), Editable] diff --git a/Barotrauma/BarotraumaShared/SharedSource/CircuitBox/CircuitBoxInputOutputNode.cs b/Barotrauma/BarotraumaShared/SharedSource/CircuitBox/CircuitBoxInputOutputNode.cs index e589401bc..99b619886 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/CircuitBox/CircuitBoxInputOutputNode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/CircuitBox/CircuitBoxInputOutputNode.cs @@ -77,8 +77,8 @@ namespace Barotrauma } else { - conn.SetLabel(conn.Connection.DisplayName, this); conn.Connection.DisplayNameOverride = null; + conn.SetLabel(conn.Connection.DisplayName, this); } } #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/CharacterFile.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/CharacterFile.cs index e608d06ba..0e67a57ef 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/CharacterFile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/CharacterFile.cs @@ -106,9 +106,10 @@ namespace Barotrauma void AddTexturePath(string path) { if (string.IsNullOrEmpty(path)) { return; } + var contentPath = ContentPath.FromRaw(characterPrefab.ContentPackage, ragdollParams.Texture); //if the path contains a gender variable, we can't load it yet because we don't know which gender we need - if (path.Contains("[GENDER]")) { return; } - texturePaths.Add(ContentPath.FromRaw(characterPrefab.ContentPackage, ragdollParams.Texture)); + if (contentPath.FullPath.Contains("[GENDER]")) { return; } + texturePaths.Add(contentPath); } } #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs index 2bee7b3c1..12967f125 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs @@ -199,9 +199,16 @@ namespace Barotrauma try { - return success(doc.Root.GetAttributeBool("corepackage", false) + ContentPackage contentPackage = doc.Root.GetAttributeBool("corepackage", false) ? new CorePackage(doc, path) - : new RegularPackage(doc, path)); + : new RegularPackage(doc, path); + + if (System.IO.Path.GetFileNameWithoutExtension(path)?.Any(char.IsUpper) is true) + { + DebugConsole.ThrowError($"Invalid filename casing. Please rename \"filelist.xml\" so it is entirely lowercase.", contentPackage: contentPackage); + } + + return success(contentPackage); } catch (Exception e) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 8dc9bb60d..c70f3a767 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -3019,7 +3019,10 @@ namespace Barotrauma switch (args[argIndex].ToLowerInvariant()) { case "inside": - spawnPoint = WayPoint.GetRandom(SpawnType.Human, job, Submarine.MainSub); + spawnPoint = + WayPoint.GetRandom(SpawnType.Human, job, Submarine.MainSub) ?? + //try a non-job-specific spawnpoint if a job-specific one can't be found + WayPoint.GetRandom(SpawnType.Human, assignedJob: null, Submarine.MainSub); break; case "outside": spawnPoint = WayPoint.GetRandom(SpawnType.Enemy); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Decals/Decal.cs b/Barotrauma/BarotraumaShared/SharedSource/Decals/Decal.cs index b42f1131c..281022315 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Decals/Decal.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Decals/Decal.cs @@ -34,11 +34,12 @@ namespace Barotrauma get { return Prefab.LifeTime; } } + private float baseAlpha = 1.0f; public float BaseAlpha { - get; - set; - } = 1.0f; + get => baseAlpha; + set => baseAlpha = MathHelper.Clamp(value, 0f, 1f); + } public Color Color { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs index 79a25913a..3f2cb74c6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs @@ -131,6 +131,14 @@ namespace Barotrauma /// OnRemoved = 25, /// + /// Executes continuously while the item/character is being deconstructed. + /// + OnDeconstructing = 26, + /// + /// Executed once when the item/character is deconstructed. + /// + OnDeconstructed = 27, + /// /// Executes when the character dies. Only valid for characters. /// OnDeath = OnBroken diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Event.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Event.cs index 08abda9ed..1c2cc3a87 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Event.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Event.cs @@ -12,7 +12,11 @@ namespace Barotrauma public readonly int RandomSeed; protected readonly EventPrefab prefab; - + +#nullable enable + public Mission? TriggeringMission; +#nullable restore + public EventPrefab Prefab => prefab; public EventSet ParentSet { get; private set; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CheckConditionalAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CheckConditionalAction.cs index 04d517c2f..b1391bd64 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CheckConditionalAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CheckConditionalAction.cs @@ -29,6 +29,9 @@ namespace Barotrauma [Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the target (or all targets if there's multiple) when the check succeeds.")] public Identifier ApplyTagToTarget { get; set; } + [Serialize(true, IsPropertySaveable.Yes, description: "Should the check fail if no targets matching the specified tag are found?")] + public bool FailIfTargetNotFound { get; set; } + public CheckConditionalAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { if (TargetTag.IsEmpty) @@ -79,11 +82,10 @@ namespace Barotrauma if (targets.None()) { - DebugConsole.LogError($"{nameof(CheckConditionalAction)} error: {GetEventDebugName()} uses a {nameof(CheckConditionalAction)} but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.", - contentPackage: ParentEvent.Prefab.ContentPackage); + return !FailIfTargetNotFound; } - if (targets.None() || Conditionals.None()) + if (Conditionals.None()) { foreach (var target in targets) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ConversationAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ConversationAction.cs index f6ff09a03..bc40eab16 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ConversationAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ConversationAction.cs @@ -14,6 +14,33 @@ namespace Barotrauma /// partial class ConversationAction : EventAction { + public class OptionActionGroup : SubactionGroup + { + [Serialize("", IsPropertySaveable.Yes, description: "The text to display in the option.")] + public string Text { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, description: "Should this option end the conversation (closing the conversation prompt?). " + + "By default, options that don't have any actions inside them, or that only have a GoTo action, end the conversation. " + + "But if there are other actions inside the option, the game assumes there may be some kind of a follow-up coming to the conversation, " + + "and by default leaves it open.")] + public bool EndConversation { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, description: $"If enabled, the player will send the {nameof(Text)} in chat when selecting the option, or if {nameof(ForceSayText)} is not empty, will send that instead.")] + public bool ForceSay { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, description: "If enabled, the message sent in chat will be sent in radio chat instead.")] + public bool ForceSayInRadio { get; set; } + + [Serialize("", IsPropertySaveable.Yes, description: $"Message sent in chat, if empty, {nameof(Text)} is used instead.")] + public string ForceSayText { get; set; } + + [Serialize(true, IsPropertySaveable.Yes, description: "Should the chat message be stripped of any quotation mark characters?")] + public bool ForceSayRemoveQuotes { get; set; } + + public OptionActionGroup(ScriptedEvent scriptedEvent, ContentXElement element) : base(scriptedEvent, element) + { + } + } public enum DialogTypes { @@ -33,6 +60,18 @@ namespace Barotrauma [Serialize("", IsPropertySaveable.Yes, description: "The text to display in the prompt. Can be the text as-is, or a tag referring to a line in a text file.")] public string Text { get; set; } + [Serialize(false, IsPropertySaveable.Yes, description: $"If enabled, the speaker will send the {nameof(Text)} in chat, or if {nameof(ForceSayText)} is not empty, will send that instead. Note: requires a valid SpeakerTag to be defined.")] + public bool ForceSay { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, description: "If enabled, the message sent in chat by the speaker will be sent in radio chat instead.")] + public bool ForceSayInRadio { get; set; } + + [Serialize("", IsPropertySaveable.Yes, description: $"Message sent in chat by the speaker, if empty, {nameof(Text)} is used instead.")] + public string ForceSayText { get; set; } + + [Serialize(true, IsPropertySaveable.Yes, description: "Should the chat message be stripped of any quotation mark characters?")] + public bool ForceSayRemoveQuotes { get; set; } + [Serialize("", IsPropertySaveable.Yes, description: "Tag of the character who's speaking. Makes a speech bubble icon appear above the character to indicate you can speak with them, and stops the character in place when the conversation triggers. Also allows the conversation to be interrupted if the speaker dies or becomes incapacitated mid-conversation.")] public Identifier SpeakerTag { get; set; } @@ -75,7 +114,7 @@ namespace Barotrauma private AIObjective prevIdleObjective, prevGotoObjective; private AIObjective npcWaitObjective; - public List Options { get; private set; } + public List Options { get; private set; } public SubactionGroup Interrupted { get; private set; } @@ -99,12 +138,12 @@ namespace Barotrauma { actionCount++; Identifier = actionCount; - Options = new List(); + Options = new List(); foreach (var elem in element.Elements()) { if (elem.Name.LocalName.Equals("option", StringComparison.OrdinalIgnoreCase)) { - Options.Add(new SubactionGroup(ParentEvent, elem)); + Options.Add(new OptionActionGroup(ParentEvent, elem)); } else if (elem.Name.LocalName.Equals("interrupt", StringComparison.OrdinalIgnoreCase)) { @@ -215,6 +254,10 @@ namespace Barotrauma interrupt = false; dialogOpened = false; Speaker = null; +#if CLIENT + dialogBox?.Close(); + dialogBox = null; +#endif } /// @@ -292,6 +335,7 @@ namespace Barotrauma if (dialogOpened) { lastActiveTime = Timing.TotalTime; + #if CLIENT if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "ConversationAction")) { @@ -350,7 +394,7 @@ namespace Barotrauma } else { - TryStartConversation(null); + TryStartConversation(Speaker); } } else @@ -467,11 +511,26 @@ namespace Barotrauma ParentEvent.AddTarget(InvokerTag, targetCharacter); } - ShowDialog(speaker, targetCharacter); + if (ForceSay) + { + speaker?.ForceSay( + ForceSayText.IsNullOrEmpty() ? TextManager.Get(Text).Fallback(Text) : TextManager.Get(ForceSayText).Fallback(ForceSayText), + ForceSayInRadio, + ForceSayRemoveQuotes, + // Small delay so the speaking character doesn't talk at the same time as the player + delay: 0.7f); + } + + ShowDialog(Speaker, targetCharacter); dialogOpened = true; - if (speaker != null) + if (Speaker != null) { + Speaker = speaker; + + // Set the Speaker of the child conversation actions so they know which character is speaking + Options.SelectMany(static op => op.Actions).OfType().ForEach(action => action.Speaker = speaker); + speaker.CampaignInteractionType = CampaignMode.InteractionType.None; speaker.SetCustomInteract(null, null); #if SERVER diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CountTargetsAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CountTargetsAction.cs index 13d3b6859..ba10a1f7e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CountTargetsAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/CountTargetsAction.cs @@ -99,6 +99,7 @@ namespace Barotrauma else { int compareToTargetCount = ParentEvent.GetTargets(CompareToTarget).Count(); + if (compareToTargetCount == 0) { return false; } float percentage = MathUtils.Percentage(targetCount, compareToTargetCount); if (MinPercentageRelativeToTarget > -1 && percentage < MinPercentageRelativeToTarget) { return false; } if (MaxPercentageRelativeToTarget > -1 && percentage > MaxPercentageRelativeToTarget) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/EventAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/EventAction.cs index f1a54e742..bf96cb286 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/EventAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/EventAction.cs @@ -9,14 +9,7 @@ namespace Barotrauma { public class SubactionGroup { - public string Text; public List Actions; - /// - /// Should this option end the conversation (closing the conversation prompt?). By default, options that don't have any actions inside them, or that only have a GoTo action, end the conversation. - /// But if there are other actions inside the option, the game assumes there may be some kind of a follow-up coming to the conversation, and by default leaves it open. - /// - public bool EndConversation; - private int currentSubAction = 0; public EventAction CurrentSubAction @@ -31,17 +24,17 @@ namespace Barotrauma } } - public SubactionGroup(ScriptedEvent scriptedEvent, ContentXElement elem) + public SubactionGroup(ScriptedEvent scriptedEvent, ContentXElement element) { - Text = elem.GetAttribute("text")?.Value ?? ""; + SerializableProperty.DeserializeProperties(this, element); + Actions = new List(); - EndConversation = elem.GetAttributeBool("endconversation", false); - foreach (var e in elem.Elements()) + foreach (var e in element.Elements()) { if (e.Name.ToString().Equals("statuseffect", StringComparison.OrdinalIgnoreCase)) { - DebugConsole.ThrowError($"Error in event prefab \"{scriptedEvent.Prefab.Identifier}\". Status effect configured as a sub action (text: \"{Text}\"). Please configure status effects as child elements of a StatusEffectAction.", - contentPackage: elem.ContentPackage); + DebugConsole.ThrowError($"Error in event prefab \"{scriptedEvent.Prefab.Identifier}\". Status effect configured as a sub action. Please configure status effects as child elements of a StatusEffectAction.", + contentPackage: element.ContentPackage); continue; } var action = Instantiate(scriptedEvent, e); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ForceSayAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ForceSayAction.cs new file mode 100644 index 000000000..1e5b933a2 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/ForceSayAction.cs @@ -0,0 +1,62 @@ +using Barotrauma.Items.Components; +using Barotrauma.Networking; +using System.Linq; + +namespace Barotrauma +{ + /// + /// Forces a specific character to say a message in chat. + /// + class ForceSayAction : EventAction + { + [Serialize("", IsPropertySaveable.Yes, description: "Tag of the character that should say the message.")] + public Identifier TargetTag { get; set; } + + [Serialize("", IsPropertySaveable.Yes, description: "The message that the character should say. Can be the text as-is, or a tag referring to a line in a text file.")] + public string Message { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, description: "Should the message that the character says be sent in radio?")] + public bool SayInRadio { get; set; } + + [Serialize(true, IsPropertySaveable.Yes, description: "Should the message be stripped of any quotation mark characters?")] + public bool RemoveQuotes { get; set; } + + public ForceSayAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { } + + private bool isFinished = false; + + public override bool IsFinished(ref string goTo) + { + return isFinished; + } + + public override void Reset() + { + isFinished = false; + } + + public override void Update(float deltaTime) + { + if (isFinished) { return; } + + var targets = ParentEvent.GetTargets(TargetTag); + + LocalizedString messageToSay = TextManager.Get(Message).Fallback(Message); + foreach (var target in targets) + { + if (target != null && target is Character character) + { + character.ForceSay(messageToSay, SayInRadio, RemoveQuotes); + } + } + + isFinished = true; + } + + public override string ToDebugString() + { + return $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(ForceSayAction)} -> (TargetTag: {TargetTag.ColorizeObject()}, " + + $"Message: {Message})"; + } + } +} \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/MissionStateAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/MissionStateAction.cs index a6dd612be..92ddc1ee3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/MissionStateAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/MissionStateAction.cs @@ -1,84 +1,77 @@ -namespace Barotrauma +#nullable enable +namespace Barotrauma; + +/// Changes the state of missions. The way the states are used depends on the type of mission. +internal sealed class MissionStateAction : EventAction { - - /// - /// Changes the state of a specific active mission. The way the states are used depends on the type of mission. - /// - class MissionStateAction : EventAction + /// The operation to perform on missions' states. + public enum OperationType { - [Serialize("", IsPropertySaveable.Yes, description: "Identifier of the mission whose state to change.")] - public Identifier MissionIdentifier { get; set; } + /// Sets the missions' states to . + Set, + /// Adds to the missions' states. + Add + } - public enum OperationType + [Serialize("", IsPropertySaveable.Yes, "Identifiers of the missions whose states to change. Leave blank to only set the state of the mission that triggered the parent event.")] + public Identifier MissionIdentifier { get; set; } + + [Serialize(OperationType.Set, IsPropertySaveable.Yes, "The operation to perform on missions' states.")] + public OperationType Operation { get; set; } + + [Serialize(0, IsPropertySaveable.Yes, "The value to apply to missions' states.")] + public int State { get; set; } + + [Serialize(false, IsPropertySaveable.Yes, "If set to true, missions are forced to fail without a chance of retrying them.")] + public bool ForceFailure { get; set; } + + public MissionStateAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) + { + State = element.GetAttributeInt("value", State); + if (Operation == OperationType.Add && State == 0 && !ForceFailure) { - Set, - Add + DebugConsole.AddWarning($"Potential error in event \"{parentEvent.Prefab.Identifier}\": {nameof(MissionStateAction)} is set to only add 0 to the mission state, which will do nothing.", + contentPackage: element.ContentPackage); } + } - [Serialize(OperationType.Set, IsPropertySaveable.Yes, description: "Should the value be added to the state of the mission, or should the state be set to the specified value.")] - public OperationType Operation { get; set; } + private bool isFinished; + public override bool IsFinished(ref string goTo) => isFinished; + public override void Reset() => isFinished = false; - [Serialize(0, IsPropertySaveable.Yes, description: "The state to set the mission to, or how much to add to the state of the mission.")] - public int State { get; set; } + public override void Update(float deltaTime) + { + if (isFinished) { return; } - [Serialize(false, IsPropertySaveable.Yes, description: "If set to true, the mission is forced to fail without a chance of retrying it.")] - public bool ForceFailure { get; set; } - - private bool isFinished; - - public MissionStateAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) + if (!MissionIdentifier.IsEmpty) { - State = element.GetAttributeInt("value", State); - if (MissionIdentifier.IsEmpty) - { - DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": MissionIdentifier has not been configured.", - contentPackage: element.ContentPackage); - } - if (Operation == OperationType.Add && State == 0 && !ForceFailure) - { - DebugConsole.AddWarning($"Potential error in event \"{parentEvent.Prefab.Identifier}\": {nameof(MissionStateAction)} is set to add 0 to the mission state, which will do nothing.", - contentPackage: element.ContentPackage); - } - } - - public override bool IsFinished(ref string goTo) - { - return isFinished; - } - public override void Reset() - { - isFinished = false; - } - - public override void Update(float deltaTime) - { - if (isFinished) { return; } - foreach (Mission mission in GameMain.GameSession.Missions) { if (mission.Prefab.Identifier != MissionIdentifier) { continue; } - if (ForceFailure) - { - mission.ForceFailure = true; - } - - switch (Operation) - { - case OperationType.Set: - mission.State = State; - break; - case OperationType.Add: - mission.State += State; - break; - } + SetMissionState(mission); } - - isFinished = true; + } + else if (ParentEvent.TriggeringMission != null) + { + SetMissionState(ParentEvent.TriggeringMission); } - public override string ToDebugString() + isFinished = true; + } + + private void SetMissionState(Mission mission) + { + if (ForceFailure) { mission.ForceFailure = true; } + switch (Operation) { - return $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(MissionStateAction)} -> ({(Operation == OperationType.Set ? State : '+' + State)})"; + case OperationType.Set: + mission.State = State; + break; + case OperationType.Add: + mission.State += State; + break; } } + + public override string ToDebugString() => $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(MissionStateAction)} -> ({(Operation == OperationType.Set ? State : '+' + State)})"; } \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCFollowAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCFollowAction.cs index 968e8c988..ed8fa1590 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCFollowAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCFollowAction.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -18,6 +18,9 @@ namespace Barotrauma [Serialize(true, IsPropertySaveable.Yes, description: "Should the NPC start or stop following the target?")] public bool Follow { get; set; } + [Serialize(false, IsPropertySaveable.Yes, description: "Should the NPC be forced to walk towards the target?")] + public bool ForceWalk { get; set; } + [Serialize(-1, IsPropertySaveable.Yes, description: "Maximum number of NPCs to target (e.g. you could choose to only make a specific number of security officers follow the player.)")] public int MaxTargets { get; set; } @@ -65,7 +68,8 @@ namespace Barotrauma var newObjective = new AIObjectiveGoTo(target, npc, humanAiController.ObjectiveManager, repeat: true) { OverridePriority = Priority, - IsFollowOrder = true + IsFollowOrder = true, + ForceWalkPermanently = ForceWalk }; humanAiController.ObjectiveManager.AddObjective(newObjective); humanAiController.ObjectiveManager.WaitTimer = 0.0f; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs index 3b28cd186..6accd385e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs @@ -271,6 +271,10 @@ namespace Barotrauma ParentEvent.AddTarget(TargetTag, newCharacter); } spawnedEntity = newCharacter; + if (newCharacter is { AIController: EnemyAIController enemyAi, Submarine: Submarine ownSub }) + { + enemyAi.SetUnattackableSubmarines(ownSub); + } }); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs index 01009f1db..195ff9fe6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs @@ -240,42 +240,45 @@ namespace Barotrauma CreateEvents(eventSet); } - if (level?.LevelData != null) + bool isOutpostLevel = level?.LevelData is { Type: LevelData.LevelType.Outpost } || + (GameMain.GameSession?.GameMode is TestGameMode && Submarine.MainSub?.Info?.Type == SubmarineType.Outpost); + if (isOutpostLevel) { - if (level.LevelData.Type == LevelData.LevelType.Outpost) + //if the outpost is connected to a locked connection, create an event to unlock it + if (level?.StartLocation?.Connections.Any(c => c.Locked && level.StartLocation.MapPosition.X < c.OtherLocation(level.StartLocation).MapPosition.X) ?? false) { - //if the outpost is connected to a locked connection, create an event to unlock it - if (level.StartLocation?.Connections.Any(c => c.Locked && level.StartLocation.MapPosition.X < c.OtherLocation(level.StartLocation).MapPosition.X) ?? false) + var unlockPathEventPrefab = EventPrefab.GetUnlockPathEvent(level.LevelData.Biome.Identifier, level.StartLocation.Faction); + if (unlockPathEventPrefab != null) { - var unlockPathEventPrefab = EventPrefab.GetUnlockPathEvent(level.LevelData.Biome.Identifier, level.StartLocation.Faction); - if (unlockPathEventPrefab != null) + var newEvent = unlockPathEventPrefab.CreateInstance(RandomSeed); + activeEvents.Add(newEvent); + } + else + { + //if no event that unlocks the path can be found, unlock it automatically + level.StartLocation.Connections.ForEach(c => c.Locked = false); + } + } + Submarine outpost = level?.StartOutpost ?? Submarine.MainSub; + if (GameMain.NetworkMember is not { IsClient: true } && outpost != null) + { + foreach (var eventTag in outpost.Info.TriggerOutpostMissionEvents) + { + EventPrefab eventPrefab = EventPrefab.FindEventPrefab(identifier: Identifier.Empty, tag: eventTag, outpost.ContentPackage); + if (eventPrefab == null) { - var newEvent = unlockPathEventPrefab.CreateInstance(RandomSeed); - activeEvents.Add(newEvent); + DebugConsole.ThrowError($"Outpost {outpost.Info.DisplayName} failed to trigger an event (tag: {eventTag}).", contentPackage: outpost.ContentPackage); } else { - //if no event that unlocks the path can be found, unlock it automatically - level.StartLocation.Connections.ForEach(c => c.Locked = false); + var newEvent = eventPrefab.CreateInstance(RandomSeed); + ActivateEvent(newEvent); } } - if (GameMain.NetworkMember is not { IsClient: true } && level.StartOutpost != null) - { - foreach (var eventTag in level.StartOutpost.Info.TriggerOutpostMissionEvents) - { - EventPrefab eventPrefab = EventPrefab.FindEventPrefab(identifier: Identifier.Empty, tag: eventTag, level.StartOutpost.ContentPackage); - if (eventPrefab == null) - { - DebugConsole.ThrowError($"Outpost {level.StartOutpost.Info.DisplayName} failed to trigger an event (tag: {eventTag}).", contentPackage: level.StartOutpost.ContentPackage); - } - else - { - var newEvent = eventPrefab.CreateInstance(RandomSeed); - ActivateEvent(newEvent); - } - } - } - } + } + } + if (level?.LevelData != null) + { RegisterNonRepeatableChildEvents(initialEventSet); void RegisterNonRepeatableChildEvents(EventSet eventSet) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AbandonedOutpostMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AbandonedOutpostMission.cs index 09703cf05..16d635b69 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AbandonedOutpostMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AbandonedOutpostMission.cs @@ -233,7 +233,7 @@ namespace Barotrauma } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return State > 0 && State != HostagesKilledState; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs index f9b102a87..70fc86b00 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs @@ -171,7 +171,7 @@ namespace Barotrauma #endif } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return level.CheckBeaconActive(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs index f62efa2ef..4768696f5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs @@ -331,7 +331,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CombatMission.cs index 64bf201c7..6b45f0ef9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CombatMission.cs @@ -204,7 +204,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return Winner != CharacterTeamType.None; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CustomMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CustomMission.cs new file mode 100644 index 000000000..d18349dbd --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CustomMission.cs @@ -0,0 +1,18 @@ +#nullable enable +namespace Barotrauma; + +/// +/// Defines a mission where the success and failure are determined solely by its state. +/// Intended to be used alongside . +/// +internal sealed partial class CustomMission(MissionPrefab prefab, Location[] locations, Submarine sub) : Mission(prefab, locations, sub) +{ + public readonly int SuccessState = prefab.ConfigElement.GetAttributeInt(nameof(SuccessState), +1); + public readonly int FailureState = prefab.ConfigElement.GetAttributeInt(nameof(FailureState), -1); + + public bool RequireDestinationReached = prefab.ConfigElement.GetAttributeBool(nameof(RequireDestinationReached), false); + + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) => + State == SuccessState && + (!RequireDestinationReached || transitionType is CampaignMode.TransitionType.ProgressToNextLocation or CampaignMode.TransitionType.ProgressToNextEmptyLocation); +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EliminateTargetsMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EliminateTargetsMission.cs index cc7855701..1bfeaea1f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EliminateTargetsMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EliminateTargetsMission.cs @@ -1,4 +1,4 @@ -using System; +using System; using Barotrauma.Extensions; using Barotrauma.RuinGeneration; using Microsoft.Xna.Framework; @@ -199,7 +199,7 @@ namespace Barotrauma private static bool IsEnemyDefeated(Character enemy) => enemy == null ||enemy.Removed || enemy.IsDead; - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { bool exitingLevel = GameMain.GameSession?.GameMode is CampaignMode campaign ? campaign.GetAvailableTransition() != CampaignMode.TransitionType.None : diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EndMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EndMission.cs index 1ffc09b93..e68af0349 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EndMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EndMission.cs @@ -1,4 +1,4 @@ -using Barotrauma.Extensions; +using Barotrauma.Extensions; using Barotrauma.Items.Components; using Microsoft.Xna.Framework; using System; @@ -301,7 +301,7 @@ namespace Barotrauma partial void OnStateChangedProjSpecific(); - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return Phase == MissionPhase.BossKilled; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EscortMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EscortMission.cs index 473006b60..3a770fffa 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EscortMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/EscortMission.cs @@ -343,7 +343,7 @@ namespace Barotrauma return character != null && !character.Removed && !character.IsDead; } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs index a1924db58..c35e7b789 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs @@ -17,7 +17,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { if (Level.Loaded?.Type == LevelData.LevelType.Outpost) { @@ -25,7 +25,7 @@ namespace Barotrauma } else { - return Submarine.MainSub is { AtEndExit: true }; + return transitionType == CampaignMode.TransitionType.ProgressToNextLocation; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MineralMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MineralMission.cs index 10d174170..d75e61fa6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MineralMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MineralMission.cs @@ -1,4 +1,4 @@ -using Barotrauma.Extensions; +using Barotrauma.Extensions; using Barotrauma.Items.Components; using Microsoft.Xna.Framework; using System; @@ -47,6 +47,12 @@ namespace Barotrauma } } + /// + /// Minerals spawned by the mission. Note that minerals that were already present in the level may have also been used as targets. + /// Each list of items represents a separate cluster of minerals. + /// + public IEnumerable> SpawnedResources => spawnedResources.Values; + public override LocalizedString SuccessMessage => ModifyMessage(base.SuccessMessage); public override LocalizedString FailureMessage => ModifyMessage(base.FailureMessage); public override LocalizedString Description => ModifyMessage(description); @@ -169,7 +175,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return EnoughHaveBeenCollected(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs index e6629022b..6dcfd314f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs @@ -401,14 +401,9 @@ namespace Barotrauma { characterItems.Add(spawnedCharacter, spawnedCharacter.Inventory.FindAllItems(recursive: true)); } - if (submarine != null && spawnedCharacter.AIController is EnemyAIController enemyAi) + if (spawnedCharacter.AIController is EnemyAIController enemyAi && submarine != null) { - enemyAi.UnattackableSubmarines.Add(submarine); - enemyAi.UnattackableSubmarines.Add(Submarine.MainSub); - foreach (Submarine sub in Submarine.MainSub.DockedTo) - { - enemyAi.UnattackableSubmarines.Add(sub); - } + enemyAi.SetUnattackableSubmarines(submarine); } InitCharacter(spawnedCharacter, element); return spawnedCharacter; @@ -532,6 +527,7 @@ namespace Barotrauma if (GameMain.GameSession?.EventManager != null) { var newEvent = eventPrefab.CreateInstance(GameMain.GameSession.EventManager.RandomSeed); + newEvent.TriggeringMission = this; GameMain.GameSession.EventManager.ActivateEvent(newEvent); } } @@ -539,13 +535,13 @@ namespace Barotrauma /// /// End the mission and give a reward if it was completed successfully /// - public void End() + public void End(CampaignMode.TransitionType transitionType) { if (GameMain.NetworkMember is not { IsClient: true }) { completed = !ForceFailure && - DetermineCompleted() && + DetermineCompleted(transitionType) && (completeCheckDataAction == null || completeCheckDataAction.GetSuccess()); } if (completed) @@ -578,7 +574,7 @@ namespace Barotrauma } } - protected abstract bool DetermineCompleted(); + protected abstract bool DetermineCompleted(CampaignMode.TransitionType transitionType); protected virtual void EndMissionSpecific(bool completed) { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs index cd32310eb..28c5e4a26 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs @@ -30,7 +30,8 @@ namespace Barotrauma { "GoTo".ToIdentifier(), typeof(GoToMission) }, { "ScanAlienRuins".ToIdentifier(), typeof(ScanMission) }, { "EliminateTargets".ToIdentifier(), typeof(EliminateTargetsMission) }, - { "End".ToIdentifier(), typeof(EndMission) } + { "End".ToIdentifier(), typeof(EndMission) }, + { "Custom".ToIdentifier(), typeof(CustomMission) } }; /// @@ -64,6 +65,7 @@ namespace Barotrauma public Type MissionClass { get; private set; } + public bool CampaignOnly { get; private set; } public bool MultiplayerOnly { get; private set; } public bool SingleplayerOnly { get; private set; } @@ -319,8 +321,9 @@ namespace Barotrauma SonarIconIdentifier = ConfigElement.GetAttributeIdentifier("sonaricon", ""); - MultiplayerOnly = ConfigElement.GetAttributeBool("multiplayeronly", false); - SingleplayerOnly = ConfigElement.GetAttributeBool("singleplayeronly", false); + CampaignOnly = ConfigElement.GetAttributeBool(nameof(CampaignOnly), false); + MultiplayerOnly = ConfigElement.GetAttributeBool(nameof(MultiplayerOnly), false); + SingleplayerOnly = ConfigElement.GetAttributeBool(nameof(SingleplayerOnly), false); AchievementIdentifier = ConfigElement.GetAttributeIdentifier("achievementidentifier", ""); @@ -543,7 +546,7 @@ namespace Barotrauma } /// - /// Returns all mission types that can be selected e.g. in the server lobby, excluding any special, hidden ones like EndMission + /// Returns all mission types that can be selected in the server lobby, excluding any special, hidden ones like EndMission /// (the mission at the end of the campaign) /// public static IEnumerable GetAllMultiplayerSelectableMissionTypes() @@ -552,6 +555,7 @@ namespace Barotrauma foreach (var missionPrefab in Prefabs) { if (missionPrefab.Commonness <= 0.0f) { continue; } + if (missionPrefab.CampaignOnly) { continue; } if (missionPrefab.SingleplayerOnly) { continue; } if (HiddenMissionTypes.Contains(missionPrefab.Type)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs index 941b7c4dd..656764b14 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs @@ -242,7 +242,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return state > 0; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/NestMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/NestMission.cs index 3ad3effe1..41dbb356a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/NestMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/NestMission.cs @@ -337,7 +337,7 @@ namespace Barotrauma return true; } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return AllItemsDestroyedOrRetrieved(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs index 6331311af..6d7f895ff 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs @@ -547,7 +547,7 @@ namespace Barotrauma return character == null || character.Removed || character.Submarine == null || (character.LockHands && character.Submarine == Submarine.MainSub) || character.IsIncapacitated; } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { return state == 2; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/SalvageMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/SalvageMission.cs index 602e4dd0d..e0a7aa4af 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/SalvageMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/SalvageMission.cs @@ -715,7 +715,7 @@ namespace Barotrauma } } - protected override bool DetermineCompleted() + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) { if (requiredDeliveryAmount < 1.0f) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs index e388b2908..a16c556fd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/ScanMission.cs @@ -1,4 +1,4 @@ -using System; +using System; using Barotrauma.Extensions; using Barotrauma.Items.Components; using Barotrauma.RuinGeneration; @@ -17,7 +17,7 @@ namespace Barotrauma private readonly Dictionary parentInventoryIDs = new Dictionary(); private readonly Dictionary inventorySlotIndices = new Dictionary(); private readonly Dictionary parentItemContainerIndices = new Dictionary(); - private readonly int targetsToScan; + private readonly int totalTargetsToScan; private readonly Dictionary scanTargets = new Dictionary(); private readonly HashSet newTargetsScanned = new HashSet(); private readonly float minTargetDistance; @@ -44,7 +44,7 @@ namespace Barotrauma public ScanMission(MissionPrefab prefab, Location[] locations, Submarine sub) : base(prefab, locations, sub) { itemConfig = prefab.ConfigElement.GetChildElement("Items"); - targetsToScan = prefab.ConfigElement.GetAttributeInt("targets", 1); + totalTargetsToScan = prefab.ConfigElement.GetAttributeInt("targets", 1); minTargetDistance = prefab.ConfigElement.GetAttributeFloat("mintargetdistance", 0.0f); } @@ -77,57 +77,60 @@ namespace Barotrauma var ruinWaypoints = TargetRuin.Submarine.GetWaypoints(false); ruinWaypoints.RemoveAll(wp => wp.CurrentHull == null); - if (ruinWaypoints.Count < targetsToScan) + if (ruinWaypoints.Count < totalTargetsToScan) { - DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {targetsToScan})", + DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {totalTargetsToScan})", contentPackage: Prefab.ContentPackage); return; } + + //the distance we'll use if we otherwise fail to place the targets far enough from each other + //(smallest extent should be large enough to fit the targets and one extra to be safe) + float guaranteedDistance = Math.Min(TargetRuin.Area.Width, TargetRuin.Area.Height) / (totalTargetsToScan + 1); + var availableWaypoints = new List(); - float minTargetDistanceSquared = minTargetDistance * minTargetDistance; - for (int tries = 0; tries < 15; tries++) + const int MaxTries = 15; + for (int tries = 0; tries < MaxTries; tries++) { + float triesNormalized = tries / (float)(MaxTries - 1); // 0.0 -> 1.0 + float desperationFactor = MathF.Pow(triesNormalized, 2); + //try placing the targets the desired minimum distance apart, gradually lowering the distance requirement on each try + float currentMinDistance = MathHelper.Lerp(minTargetDistance, guaranteedDistance, desperationFactor); + float currentMinDistanceSquared = currentMinDistance * currentMinDistance; + scanTargets.Clear(); availableWaypoints.Clear(); availableWaypoints.AddRange(ruinWaypoints); - for (int i = 0; i < targetsToScan; i++) + for (int i = 0; i < totalTargetsToScan; i++) { var selectedWaypoint = availableWaypoints.GetRandom(randSync: Rand.RandSync.ServerAndClient); scanTargets.Add(selectedWaypoint, false); availableWaypoints.Remove(selectedWaypoint); - if (i < (targetsToScan - 1)) + if (i < (totalTargetsToScan - 1)) { availableWaypoints.RemoveAll(wp => wp.CurrentHull == selectedWaypoint.CurrentHull); - availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < minTargetDistanceSquared); + availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < currentMinDistanceSquared); if (availableWaypoints.None()) { #if DEBUG - DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})", + DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {totalTargetsToScan})", contentPackage: Prefab.ContentPackage); #endif break; } } } - if (scanTargets.Count >= targetsToScan) + if (scanTargets.Count >= totalTargetsToScan) { #if DEBUG DebugConsole.NewMessage($"Successfully initialized a Scan mission: targets set on try #{tries + 1}", Color.Green); #endif break; } - if ((tries + 1) % 5 == 0) - { - float reducedMinTargetDistance = (1.0f - (((tries + 1) / 5) * 0.1f)) * minTargetDistance; - minTargetDistanceSquared = reducedMinTargetDistance * reducedMinTargetDistance; -#if DEBUG - DebugConsole.NewMessage($"Reducing minimum distance between Scan mission targets (new min: {reducedMinTargetDistance}) to reach the required target count", Color.Yellow); -#endif - } } - if (scanTargets.Count < targetsToScan) + if (scanTargets.Count < totalTargetsToScan) { - DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {targetsToScan})", + DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {totalTargetsToScan})", contentPackage: Prefab.ContentPackage); } } @@ -241,9 +244,9 @@ namespace Barotrauma State = Math.Max(State, scanTargets.Count(kvp => kvp.Value)); } - private bool AllTargetsScanned() => State >= targetsToScan; + private bool AllTargetsScanned() => State >= totalTargetsToScan; - protected override bool DetermineCompleted() => AllTargetsScanned(); + protected override bool DetermineCompleted(CampaignMode.TransitionType transitionType) => AllTargetsScanned(); protected override void EndMissionSpecific(bool completed) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsConsent.cs b/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsConsent.cs index 129fa3d25..6edea3673 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsConsent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameAnalytics/GameAnalyticsConsent.cs @@ -104,7 +104,7 @@ namespace Barotrauma return authTicket.TryUnwrap(out var ticketUnwrapped) && ticketUnwrapped.Data is { Length: > 0 } ? new AuthTicket(ToolBoxCore.ByteArrayToHexString(ticketUnwrapped.Data), Platform.Steam) //convert byte array to hex - : throw new Exception("Could not retrieve Steamworks authentication ticket for GameAnalytics"); + : throw new Exception("Could not retrieve Steam authentication ticket, possibly due to connection issues. GameAnalytics logging will be disabled."); } private static async Task GetEOSAuthTicket() @@ -215,9 +215,8 @@ namespace Barotrauma IRestResponse response; try { - var client = new RestClient(consentServerUrl); - - var request = new RestRequest(consentServerFile, Method.GET); + var client = RestFactory.CreateClient(consentServerUrl); + var request = RestFactory.CreateRequest(consentServerFile); request.AddParameter("authticket", authTicket.Token); if (consent == Consent.Ask) { @@ -321,7 +320,7 @@ namespace Barotrauma RestClient client; try { - client = new RestClient(consentServerUrl); + client = RestFactory.CreateClient(consentServerUrl); } catch (Exception e) { @@ -329,7 +328,7 @@ namespace Barotrauma return Consent.Error; } - var request = new RestRequest(consentServerFile, Method.GET); + var request = RestFactory.CreateRequest(consentServerFile); request.AddParameter("authticket", authTicket.Token); request.AddParameter("action", "getconsent"); request.AddParameter("request_version", RemoteRequestVersion); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs index daa20659a..ae18a5a21 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs @@ -1017,7 +1017,7 @@ namespace Barotrauma UpdateStoreStock(); } - GameMain.GameSession.EndMissions(); + GameMain.GameSession.EndMissions(TransitionType.None); GameMain.GameSession.EventManager?.StoreEventDataAtRoundEnd(registerFinishedOnly: true); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MissionMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MissionMode.cs index e00bf540b..d19250e5e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MissionMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MissionMode.cs @@ -53,6 +53,7 @@ namespace Barotrauma { foreach (MissionPrefab missionPrefab in missionPrefabs) { + if (missionPrefab.CampaignOnly) { continue; } if (!missionClasses.ContainsValue(missionPrefab.MissionClass)) { throw new InvalidOperationException($"Cannot start gamemode with a {missionPrefab.MissionClass} mission."); @@ -68,7 +69,7 @@ namespace Barotrauma { return missionTypes.Where(type => MissionPrefab.Prefabs.OrderBy(missionPrefab => missionPrefab.UintIdentifier) - .Any(missionPrefab => missionPrefab.Type == type && missionClasses.ContainsValue(missionPrefab.MissionClass))); + .Any(missionPrefab => missionPrefab.Type == type && !missionPrefab.CampaignOnly && missionClasses.ContainsValue(missionPrefab.MissionClass))); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs index 79e38a2f7..5174ef002 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs @@ -1,16 +1,17 @@ #nullable enable +using Barotrauma.Extensions; using Barotrauma.IO; using Barotrauma.Items.Components; +using Barotrauma.Networking; +using Barotrauma.PerkBehaviors; +using FarseerPhysics; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Xml.Linq; -using Barotrauma.Networking; -using Barotrauma.Extensions; -using Barotrauma.PerkBehaviors; namespace Barotrauma { @@ -952,14 +953,6 @@ namespace Barotrauma sub.SetPosition(spawnPos); myPort.Dock(outPostPort); myPort.Lock(isNetworkMessage: true, applyEffects: false); - foreach (var item in sub.GetItems(alsoFromConnectedSubs: true)) - { - //need to refresh position to maintain since the sub was moved to the docking port - if (item.GetComponent() is { MaintainPos: true } steering) - { - steering.RefreshPosToMaintain(); - } - } } else { @@ -982,6 +975,16 @@ namespace Barotrauma sub.EnableMaintainPosition(); } + foreach (var item in sub.GetItems(alsoFromConnectedSubs: true)) + { + // Refresh pos to maintain in all steering components maintaining + // position, including ones in shuttles, since the submarines moved + if (item.GetComponent() is { MaintainPos: true } steering) + { + steering.RefreshPosToMaintain(); + } + } + // Make sure that linked subs which are NOT docked to the main sub // (but still close enough to NOT be considered as 'left behind') // are also moved to keep their relative position to the main sub @@ -1094,7 +1097,7 @@ namespace Barotrauma ImmutableHashSet crewCharacters = GetSessionCrewCharacters(CharacterType.Both); int prevMoney = GetAmountOfMoney(crewCharacters); - EndMissions(); + EndMissions(transitionType); foreach (Character character in crewCharacters) { @@ -1197,12 +1200,12 @@ namespace Barotrauma } } - public void EndMissions() + public void EndMissions(CampaignMode.TransitionType transitionType) { ImmutableHashSet crewCharacters = GetSessionCrewCharacters(CharacterType.Both); foreach (Mission mission in missions) { - mission.End(); + mission.End(transitionType); } if (missions.Any()) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs index 98b9bd60a..146f6b603 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/CharacterInventory.cs @@ -43,8 +43,12 @@ namespace Barotrauma public InvSlotType[] SlotTypes { get; - private set; } + + /// + /// Optimization for fast access of by . + /// + private readonly Dictionary> slotsByType = []; public static readonly List AnySlot = new List { InvSlotType.Any }; public static readonly List BagSlot = new List { InvSlotType.Bag }; @@ -106,9 +110,20 @@ namespace Barotrauma case InvSlotType.RightHand: slots[i].HideIfEmpty = true; break; - } + } } - + + for (int i = 0; i < capacity; i++) + { + InvSlotType slotType = SlotTypes[i]; + if (!slotsByType.TryGetValue(slotType, out List slotList)) + { + slotList = []; + slotsByType[SlotTypes[i]] = slotList; + } + slotList.Add(slots[i]); + } + InitProjSpecific(element); var itemElements = element.Elements().Where(e => e.Name.ToString().Equals("item", StringComparison.OrdinalIgnoreCase)); @@ -198,39 +213,55 @@ namespace Barotrauma public Item GetItemInLimbSlot(InvSlotType limbSlot) { - for (int i = 0; i < slots.Length; i++) + if (slotsByType.TryGetValue(limbSlot, out List slotList)) { - if (SlotTypes[i] == limbSlot) { return slots[i].FirstOrDefault(); } + return slotList.First().FirstOrDefault(); } return null; } + public IEnumerable GetItemsInLimbSlot(InvSlotType limbSlot) + { + if (slotsByType.TryGetValue(limbSlot, out List slotList)) + { + foreach (var slot in slotList) + { + foreach (Item item in slot.Items) + { + yield return item; + } + } + } + } public bool IsInLimbSlot(Item item, InvSlotType limbSlot) { if (limbSlot == (InvSlotType.LeftHand | InvSlotType.RightHand)) { - int rightHandSlot = FindLimbSlot(InvSlotType.RightHand); - int leftHandSlot = FindLimbSlot(InvSlotType.LeftHand); - if (rightHandSlot > -1 && slots[rightHandSlot].Contains(item) && - leftHandSlot > -1 && slots[leftHandSlot].Contains(item)) + if (GetItemsInLimbSlot(InvSlotType.RightHand).Contains(item) && + GetItemsInLimbSlot(InvSlotType.LeftHand).Contains(item)) { return true; } } - - for (int i = 0; i < slots.Length; i++) + else if (slotsByType.TryGetValue(limbSlot, out List slotList)) { - if (SlotTypes[i] == limbSlot && slots[i].Contains(item)) { return true; } + foreach (ItemSlot slot in slotList) + { + if (slot.Contains(item)) { return true; } + } } return false; } public bool IsSlotEmpty(InvSlotType limbSlot) { - for (int i = 0; i < slots.Length; i++) + if (slotsByType.TryGetValue(limbSlot, out List slotList)) { - if (SlotTypes[i] == limbSlot && slots[i].Empty()) { return true; } + foreach (ItemSlot slot in slotList) + { + if (slot.Empty()) { return true; } + } } return false; } @@ -370,7 +401,7 @@ namespace Barotrauma /// /// If there is room, puts the item in the inventory and returns true, otherwise returns false /// - public override bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false) + public override bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { if (allowedSlots == null || !allowedSlots.Any()) { return false; } if (item == null) @@ -494,8 +525,6 @@ namespace Barotrauma return placedInSlot > -1; } - - public bool IsAnySlotAvailable(Item item) => GetFreeAnySlot(item, inWrongSlot: false) > -1; private int GetFreeAnySlot(Item item, bool inWrongSlot) @@ -542,7 +571,7 @@ namespace Barotrauma return -1; } - public override bool TryPutItem(Item item, int index, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false) + public override bool TryPutItem(Item item, int index, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { if (index < 0 || index >= slots.Length) { @@ -590,9 +619,9 @@ namespace Barotrauma return TryPutItem(item, user, new List() { placeToSlots }, createNetworkEvent, ignoreCondition); } - protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true) + protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true, bool triggerOnInsertedEffects = true) { - base.PutItem(item, i, user, removeItem, createNetworkEvent); + base.PutItem(item, i, user, removeItem, createNetworkEvent, triggerOnInsertedEffects); #if CLIENT CreateSlots(); if (character == Character.Controlled) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs index dacf4103a..75155b00c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs @@ -739,6 +739,12 @@ namespace Barotrauma.Items.Components { picker.Inventory.FlashAllowedSlots(item, Color.Red); } + else + { + //normally this would be done in the base.OnPicked method, but clients don't call it, + //but instead rely on the server telling them to put the item in the inventory + SoundPlayer.PlayUISound(GUISoundType.PickItem); + } return false; } #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs index d27ca9cd6..a94b6f7ef 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs @@ -347,18 +347,9 @@ namespace Barotrauma.Items.Components } else if (f2.Body.UserData is Character targetCharacter) { - if (targetCharacter == picker || targetCharacter == User) { return false; } - if (targetCharacter.IgnoreMeleeWeapons) { return false; } - if (HitFriendlyTarget(targetCharacter)) { return false; } - if (AllowHitMultiple) - { - if (hitTargets.Contains(targetCharacter)) { return false; } - } - else - { - if (hitTargets.Any(t => t is Character)) { return false; } - } - hitTargets.Add(targetCharacter); + //only allow hitting limbs, not the main collider + //otherwise it's difficult to make certain parts of the ragdoll not take hits by making them ignore collisions or melee weapons + return false; } else if (!HitOnlyCharacters) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemComponent.cs index 58d4ddc3c..75976e215 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemComponent.cs @@ -378,7 +378,7 @@ namespace Barotrauma.Items.Components break; case "requireditem": case "requireditems": - SetRequiredItems(subElement); + SetRequiredItems(subElement, allowEmpty: true); break; case "requiredskill": case "requiredskills": @@ -1100,6 +1100,9 @@ namespace Barotrauma.Items.Components foreach (RelatedItem ri in DisabledRequiredItems) { XElement newElement = new XElement("requireditem"); + //if we have some actual requirements, no need to keep the empty requirement + //as a "placeholder" for the user to add requirements in the sub editor + if (ri.Identifiers.IsEmpty && RequiredItems.Any()) { continue; } ri.Save(newElement); componentElement.Add(newElement); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs index ae7016391..561fa6716 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs @@ -99,7 +99,7 @@ namespace Barotrauma.Items.Components } } - [Serialize("0.0,0.0", IsPropertySaveable.No, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")] + [Serialize("0.0,0.0", IsPropertySaveable.No, description: "The position where the contained items get drawn at. In the case of items with a physics body, the offset is from the center of the body, on items without one from the top-left corner of the sprite. In pixels.")] public Vector2 ItemPos { get; set; } [Serialize("0.0,0.0", IsPropertySaveable.No, description: "The interval at which the contained items are spaced apart from each other (in pixels).")] @@ -425,7 +425,7 @@ namespace Barotrauma.Items.Components partial void InitProjSpecific(ContentXElement element); - public void OnItemContained(Item containedItem) + public void OnItemContained(Item containedItem, bool triggerOnInsertedEffects = true) { int index = Inventory.FindIndex(containedItem); RelatedItem relatedItem = null; @@ -444,14 +444,20 @@ namespace Barotrauma.Items.Components ActiveContainedItem activeContainedItem = new(containedItem, effect, containableItem.ExcludeBroken, containableItem.ExcludeFullCondition, containableItem.BlameEquipperForDeath); activeContainedItems.Add(activeContainedItem); - if (!ShouldApplyEffects(activeContainedItem) || item.Submarine is { Loading: true} || initializingLoadedItems || - containedItem.OnInsertedEffectsApplied) - { - continue; + if (triggerOnInsertedEffects) + { + if (!ShouldApplyEffects(activeContainedItem) || item.Submarine is { Loading: true} || initializingLoadedItems || + containedItem.OnInsertedEffectsApplied) + { + continue; + } + activeContainedItem.StatusEffect.Apply(ActionType.OnInserted, deltaTime: 1, item, targets); } - activeContainedItem.StatusEffect.Apply(ActionType.OnInserted, deltaTime: 1, item, targets); } - containedItem.OnInsertedEffectsApplied = true; + if (triggerOnInsertedEffects) + { + containedItem.OnInsertedEffectsApplied = true; + } } } } @@ -1087,21 +1093,25 @@ namespace Barotrauma.Items.Components { if (item.body == null) { + //if the item is a holdable item currently attached to a wall (i.e. normally has a physics body, but the body is now disabled), + //we must position the contained items using the center as the origin since the item positions have been configured with the assumption the item has a body + bool isAttachedHoldable = item.GetComponent() is { Attached: true }; + bool useCenterAsOrigin = isAttachedHoldable; if (flippedX) { transformedItemPos.X = -transformedItemPos.X; - transformedItemPos.X += item.Rect.Width; + if (!useCenterAsOrigin) { transformedItemPos.X += item.Rect.Width; } transformedItemInterval.X = -transformedItemInterval.X; transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X; } if (flippedY) { transformedItemPos.Y = -transformedItemPos.Y; - transformedItemPos.Y -= item.Rect.Height; + if (!useCenterAsOrigin) { transformedItemPos.Y -= item.Rect.Height; } transformedItemInterval.Y = -transformedItemInterval.Y; transformedItemIntervalVertical.Y = -transformedItemIntervalVertical.Y; } - transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y); + transformedItemPos += useCenterAsOrigin ? item.Position : new Vector2(item.Rect.X, item.Rect.Y); if (drawPosition) { if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/LinkedControllerCharacterComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/LinkedControllerCharacterComponent.cs new file mode 100644 index 000000000..6faa6db36 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/LinkedControllerCharacterComponent.cs @@ -0,0 +1,121 @@ +#nullable enable + +using Barotrauma.Networking; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Xml.Linq; + +namespace Barotrauma.Items.Components +{ + /// + /// Item component used by for keeping a reference to the character that is currently + /// selecting the controller. Also provides functionality for changing the inventory sprite of the item based on the linked character. + /// + partial class LinkedControllerCharacterComponent : ItemComponent, IServerSerializable + { +#if CLIENT + private class SpriteOverride + { + public readonly Sprite? Sprite; + public readonly Identifier SpeciesName; + public readonly Identifier SpeciesGroup; + public SpriteOverride(ContentXElement element) + { + if (element.GetChildElement("Sprite") is ContentXElement spriteElement) + { + Sprite = new Sprite(spriteElement); + } + SpeciesName = element.GetAttributeIdentifier("speciesname", Identifier.Empty); + SpeciesGroup = element.GetAttributeIdentifier("speciesgroup", Identifier.Empty); + } + } + + private readonly ImmutableArray spriteOverrides; +#endif + + [Serialize(0.5f, IsPropertySaveable.No, description: $"Maximum value which {nameof(DeconstructTimeMultiplier)} can be.")] + public float MaxDeconstructTimeMultiplier + { + get; + set; + } + + public Character? Character { get; private set; } + + public bool DoesBleed => Character?.DoesBleed == true; + + public float DeconstructTimeMultiplier { get; private set; } = 1f; + + public LinkedControllerCharacterComponent(Item item, ContentXElement element) : base(item, element) + { +#if CLIENT + spriteOverrides = element.Elements() + .Where(static e => e.Name.LocalName.ToLowerInvariant() == "spriteoverride") + .Select(static e => new SpriteOverride(e)) + .ToImmutableArray(); +#endif + } + + public void UpdateLinkedCharacter(Character? character) + { + Character = character; + + if (character != null) + { + var animController = character.AnimController; + float totalLimbs = animController.Limbs.Length; + float nonSeveredLimbs = animController.Limbs.Count(static l => !l.IsSevered); + + // Decrease deconstruction time if the character is missing some limbs + DeconstructTimeMultiplier *= MathF.Max(MaxDeconstructTimeMultiplier, nonSeveredLimbs / totalLimbs); + } + +#if CLIENT + if (character != null) + { + SpriteOverride? spriteOverride = + spriteOverrides.Where(s => s.SpeciesName == character.SpeciesName).FirstOrDefault() + ?? spriteOverrides.Where(s => s.SpeciesGroup == character.Group).FirstOrDefault(); + + if (spriteOverride != null) + { + item.OverrideInventorySprite = spriteOverride.Sprite; + } + } + else + { + item.OverrideInventorySprite = null; + } +#elif SERVER + Item.CreateServerEvent(this); +#endif + } + + public void ClientEventRead(IReadMessage msg, float sendingTime) + { + UInt16 characterId = msg.ReadUInt16(); + if (characterId == Entity.NullEntityID) + { + UpdateLinkedCharacter(null); + } + else if (Entity.FindEntityByID(characterId) is Character character) + { + UpdateLinkedCharacter(character); + } + } + + public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData? extraData = null) + { + if (Character != null) + { + msg.WriteUInt16(Character.ID); + } + else + { + msg.WriteUInt16(Entity.NullEntityID); + } + } + } +} \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs index 899258e4f..b9c3222ba 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Controller.cs @@ -1,9 +1,12 @@ -using FarseerPhysics; -using Barotrauma.Networking; +using Barotrauma.Networking; +using FarseerPhysics; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.ComponentModel; using System.Globalization; +using System.Linq; using System.Xml.Linq; namespace Barotrauma.Items.Components @@ -45,6 +48,39 @@ namespace Barotrauma.Items.Components private Camera cam; private Character user; + public Character User + { + get { return user; } + private set + { + if (user == value) + { + return; + } + + user = value; + + if (user != null) + { + teleportTransition = 0f; + teleportStartPosition = user.WorldPosition; + } +#if SERVER + item.CreateServerEvent(this); +#endif + +#if CLIENT + UpdateMsg(); + + if (HideAllItemComponentHUDs && Character.Controlled == user) + { + // Prevents any UIs in this item from briefly showing up when you select this controller, since + // activeHUDs would take a single frame to be updated to not contain any other item component HUD + Item.ClearActiveHUDs(); + } +#endif + } + } private Item focusTarget; private float targetRotation; @@ -55,11 +91,6 @@ namespace Barotrauma.Items.Components set { userPos = value; } } - public Character User - { - get { return user; } - } - public IEnumerable LimbPositions { get { return limbPositions; } } [Editable, Serialize(false, IsPropertySaveable.No, description: "When enabled, the item will continuously send out a signal and interacting with it will flip the signal (making the item behave like a switch). When disabled, the item will simply send out a signal when interacted with.", alwaysUseInstanceValues: true)] @@ -123,6 +154,13 @@ namespace Barotrauma.Items.Components set; } + [Serialize(false, IsPropertySaveable.No, description: "Should the HUDs of all item components in this item be hidden when a character is using this controller.")] + public bool HideAllItemComponentHUDs + { + get; + set; + } + public enum UseEnvironment { Air, Water, Both @@ -152,6 +190,49 @@ namespace Barotrauma.Items.Components set; } + [Serialize(false, IsPropertySaveable.No, description: "Can a character put another character into this controller by dragging them and selecting this controller?")] + public bool AllowPuttingInOtherCharacters + { + get; + set; + } + + [Serialize(true, IsPropertySaveable.No, description: "Can a character select this controller by themselves?")] + public bool CanBeSelectedByCharacters + { + get; + set; + } + + [Serialize(false, IsPropertySaveable.No, description: "If a character selects this controller, but another character already has it selected, should it be kicked out?")] + public bool SelectingKicksCharacterOut + { + get; + set; + } + + [Serialize("", IsPropertySaveable.No, description: "Message displayed when there's a character inside this controller.")] + public string KickOutCharacterMsg + { + get; + set; + } + + [Serialize("", IsPropertySaveable.No, description: "Message displayed when you are putting a character into the controller.")] + public string PutOtherCharacterMsg + { + get; + set; + } + + + [Serialize("", IsPropertySaveable.No, description: "Spawns this item in the first available item container slot when a character selects this controller, if the item container is full, the character will not be able to select the controller.")] + public Identifier SpawnItemOnSelected + { + get; + private set; + } + public bool ControlCharacterPose { get { return limbPositions.Count > 0; } @@ -204,6 +285,23 @@ namespace Barotrauma.Items.Components set; } + /// + /// Used to determine how fast the character is teleported + /// to the item when they first select the controller. + /// Only relevant for + /// + private const float TeleportTransitionSpeed = 8f; + private float teleportTransition = 0f; + private Vector2 teleportStartPosition; + + private readonly ItemPrefab spawnItemOnSelectedPrefab; + private readonly ItemContainer containerToSpawnOnSelectedItem; + + /// + /// Item spawned by + /// + private Item spawnedItemOnSelected = null; + public Controller(Item item, ContentXElement element) : base(item, element) { @@ -211,6 +309,18 @@ namespace Barotrauma.Items.Components Enum.TryParse(element.GetAttributeString("direction", "None"), out dir); LoadLimbPositions(element); IsActive = true; + + containerToSpawnOnSelectedItem = item.GetComponent(); + + if (!SpawnItemOnSelected.IsEmpty && !ItemPrefab.Prefabs.TryGet(SpawnItemOnSelected, out spawnItemOnSelectedPrefab)) + { + DebugConsole.ThrowError($"Failed to find item prefab \"{SpawnItemOnSelected}\""); + } + + if (containerToSpawnOnSelectedItem == null && !SpawnItemOnSelected.IsEmpty) + { + DebugConsole.ThrowError($"Error - Controller has a {nameof(SpawnItemOnSelected)} but no ItemContainer defined"); + } } /// @@ -236,58 +346,77 @@ namespace Barotrauma.Items.Components item.SendSignal(signal, "trigger_out"); } - if (forceSelectNextFrame && user != null) + if (forceSelectNextFrame && User != null) { - user.SelectedItem = item; + User.SelectedItem = item; } forceSelectNextFrame = false; userCanInteractCheckTimer -= deltaTime; - if (user == null - || user.Removed - || !user.IsAnySelectedItem(item) - || (item.ParentInventory != null && !IsAttachedUser(user)) - || (UsableIn == UseEnvironment.Water && !user.AnimController.InWater) - || (UsableIn == UseEnvironment.Air && user.AnimController.InWater) - || !CheckUserCanInteract()) + if (User == null + || User.Removed + || (((User.Stun <= 0f && !User.IsKnockedDownOrRagdolled && !User.LockHands) || !ForceUserToStayAttached) && (!User.IsAnySelectedItem(item) || !CheckUserCanInteract())) + || (item.ParentInventory != null && !IsAttachedUser(User)) + || (UsableIn == UseEnvironment.Water && !User.AnimController.InWater) + || (UsableIn == UseEnvironment.Air && User.AnimController.InWater) + || !CheckSpawnItem() + ) { - if (user != null) + if (User != null) { - CancelUsing(user); - user = null; + CancelUsing(User); + User = null; } if (item.Connections == null || !IsToggle || string.IsNullOrEmpty(signal)) { IsActive = false; } return; } - if (ForceUserToStayAttached && Vector2.DistanceSquared(item.WorldPosition, user.WorldPosition) > 0.1f) + if (ForceUserToStayAttached) { - user.TeleportTo(item.WorldPosition); - user.AnimController.Collider.ResetDynamics(); - foreach (var limb in user.AnimController.Limbs) + teleportTransition = MathF.Min(teleportTransition + deltaTime * TeleportTransitionSpeed, 1f); + + if (teleportTransition >= 1f) { - if (limb.Removed || limb.IsSevered) { continue; } - limb.body?.ResetDynamics(); + // Transition is complete, if someone was holding this character, force them to deselect + // so they aren't holding the character that is now attached to the controller + if (User.SelectedBy != null) + { + User.SelectedBy.SelectedCharacter = null; + } + } + + if (User == Character.Controlled + || teleportTransition < 1f + || Vector2.DistanceSquared(item.WorldPosition, User.WorldPosition) > 0.1f) + { + var targetPosition = Vector2.Lerp(teleportStartPosition, item.WorldPosition, teleportTransition); + User.TeleportTo(targetPosition); + User.AnimController.Collider.ResetDynamics(); + foreach (var limb in User.AnimController.Limbs) + { + if (limb.Removed || limb.IsSevered) { continue; } + limb.body?.ResetDynamics(); + } } } - user.AnimController.StartUsingItem(); + User.AnimController.StartUsingItem(); if (userPos != Vector2.Zero) { - Vector2 diff = (item.WorldPosition + userPos) - user.WorldPosition; + Vector2 diff = (item.WorldPosition + userPos) - User.WorldPosition; - if (user.AnimController.InWater) + if (User.AnimController.InWater) { if (diff.LengthSquared() > 30.0f * 30.0f) { - user.AnimController.TargetMovement = Vector2.Clamp(diff * 0.01f, -Vector2.One, Vector2.One); - user.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left; + User.AnimController.TargetMovement = Vector2.Clamp(diff * 0.01f, -Vector2.One, Vector2.One); + User.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left; } else { - user.AnimController.TargetMovement = Vector2.Zero; + User.AnimController.TargetMovement = Vector2.Zero; UserInCorrectPosition = true; } } @@ -295,10 +424,10 @@ namespace Barotrauma.Items.Components { // Secondary items (like ladders or chairs) will control the character position over primary items // Only control the character position if the character doesn't have another secondary item already controlling it - if (!user.HasSelectedAnotherSecondaryItem(Item)) + if (!User.HasSelectedAnotherSecondaryItem(Item)) { diff.Y = 0.0f; - if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && user != Character.Controlled) + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && User != Character.Controlled) { if (Math.Abs(diff.X) > 20.0f) { @@ -308,48 +437,48 @@ namespace Barotrauma.Items.Components else if (Math.Abs(diff.X) > 0.1f) { //aim to keep the collider at the correct position once close enough - user.AnimController.Collider.LinearVelocity = new Vector2( + User.AnimController.Collider.LinearVelocity = new Vector2( diff.X * 0.1f, - user.AnimController.Collider.LinearVelocity.Y); + User.AnimController.Collider.LinearVelocity.Y); } } else if (Math.Abs(diff.X) > 10.0f) { - user.AnimController.TargetMovement = Vector2.Normalize(diff); - user.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left; + User.AnimController.TargetMovement = Vector2.Normalize(diff); + User.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left; return; } - user.AnimController.TargetMovement = Vector2.Zero; + User.AnimController.TargetMovement = Vector2.Zero; } UserInCorrectPosition = true; } } - ApplyStatusEffects(ActionType.OnActive, deltaTime, user); + ApplyStatusEffects(ActionType.OnActive, deltaTime, User); if (limbPositions.Count == 0) { return; } - user.AnimController.StartUsingItem(); + User.AnimController.StartUsingItem(); - if (user.SelectedItem != null) + if (User.SelectedItem != null) { - user.AnimController.ResetPullJoints(l => l.IsLowerBody); + User.AnimController.ResetPullJoints(l => l.IsLowerBody); } else { - user.AnimController.ResetPullJoints(); + User.AnimController.ResetPullJoints(); } - if (dir != 0) { user.AnimController.TargetDir = dir; } + if (dir != 0) { User.AnimController.TargetDir = dir; } foreach (LimbPos lb in limbPositions) { - Limb limb = user.AnimController.GetLimb(lb.LimbType); + Limb limb = User.AnimController.GetLimb(lb.LimbType); if (limb == null || !limb.body.Enabled) { continue; } // Don't move lower body limbs if there's another selected secondary item that should control them - if (limb.IsLowerBody && user.HasSelectedAnotherSecondaryItem(Item)) { continue; } + if (limb.IsLowerBody && User.HasSelectedAnotherSecondaryItem(Item)) { continue; } // Don't move hands if there's a selected primary item that should control them - if (limb.IsArm && Item == user.SelectedSecondaryItem && user.SelectedItem != null) { continue; } + if (limb.IsArm && Item == User.SelectedSecondaryItem && User.SelectedItem != null) { continue; } if (lb.AllowUsingLimb) { switch (lb.LimbType) @@ -357,12 +486,12 @@ namespace Barotrauma.Items.Components case LimbType.RightHand: case LimbType.RightForearm: case LimbType.RightArm: - if (user.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null) { continue; } + if (User.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null) { continue; } break; case LimbType.LeftHand: case LimbType.LeftForearm: case LimbType.LeftArm: - if (user.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null) { continue; } + if (User.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null) { continue; } break; } } @@ -374,15 +503,77 @@ namespace Barotrauma.Items.Components } } + private bool IsSpawnContainerFull() + { + if (spawnItemOnSelectedPrefab == null || containerToSpawnOnSelectedItem == null) + { + return false; + } + + if (containerToSpawnOnSelectedItem.Inventory.IsFull()) + { + return true; + } + + return false; + } + + private bool CheckSpawnItem() + { + if (spawnItemOnSelectedPrefab == null || containerToSpawnOnSelectedItem == null) + { + return true; + } + + if (containerToSpawnOnSelectedItem.Inventory.AllItems.Any(x => x.Prefab == spawnItemOnSelectedPrefab)) + { + return true; + } + + if (spawnedItemOnSelected != null && !spawnedItemOnSelected.Removed) + { + if (spawnedItemOnSelected.ParentInventory != containerToSpawnOnSelectedItem.Inventory) + { + // Item was moved or dropped, force the user in this controller out + return false; + } + else + { + return true; + } + } + + if (IsSpawnContainerFull()) + { + return false; + } + + if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) + { + Entity.Spawner.AddItemToSpawnQueue(spawnItemOnSelectedPrefab, containerToSpawnOnSelectedItem.Inventory, onSpawned: spawnedItem => + { + spawnedItemOnSelected = spawnedItem; + + var linkedCharacterComponent = spawnedItem.GetComponent(); + if (linkedCharacterComponent != null) + { + linkedCharacterComponent.UpdateLinkedCharacter(User); + } + }); + } + + return true; + } + private bool CheckUserCanInteract() { //optimization: CanInteractWith is relatively heavy (can involve visibility checks for example), let's not do it every frame - if (user != null) + if (User != null) { if (userCanInteractCheckTimer <= 0.0f) { userCanInteractCheckTimer = UserCanInteractCheckInterval; - return user.CanInteractWith(item); + return User.CanInteractWith(item); } } //we only do the actual check every UserCanInteractCheckInterval seconds @@ -394,13 +585,13 @@ namespace Barotrauma.Items.Components public override bool Use(float deltaTime, Character activator = null) { - if (activator != user) + if (activator != User) { return false; } - if (user == null || user.Removed || !user.IsAnySelectedItem(item) || !user.CanInteractWith(item)) + if (User == null || User.Removed || !User.IsAnySelectedItem(item) || !User.CanInteractWith(item)) { - user = null; + User = null; return false; } @@ -419,7 +610,7 @@ namespace Barotrauma.Items.Components } else if (!string.IsNullOrEmpty(output)) { - item.SendSignal(new Signal(output, sender: user), "trigger_out"); + item.SendSignal(new Signal(output, sender: User), "trigger_out"); } lastUsed = Timing.TotalTime; @@ -428,13 +619,13 @@ namespace Barotrauma.Items.Components public override bool SecondaryUse(float deltaTime, Character character = null) { - if (user != character) + if (User != character) { return false; } - if (user == null || character.Removed || !user.IsAnySelectedItem(item) || !character.CanInteractWith(item)) + if (User == null || character.Removed || !User.IsAnySelectedItem(item) || !character.CanInteractWith(item)) { - user = null; + User = null; return false; } if (character == null) @@ -495,7 +686,7 @@ namespace Barotrauma.Items.Components if (IsOutOfPower()) { return null; } - item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), positionOut); + item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: User), positionOut); for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--) { @@ -547,8 +738,20 @@ namespace Barotrauma.Items.Components private void CancelUsing(Character character) { + if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) + { + if (spawnedItemOnSelected != null) + { + Entity.Spawner.AddEntityToRemoveQueue(spawnedItemOnSelected); + spawnedItemOnSelected = null; + } + } + if (character == null || character.Removed) { return; } + // Wake character's colliders so they don't just float in the air when taken out of the controller + character.AnimController.BodyInRest = false; + foreach (LimbPos lb in limbPositions) { Limb limb = character.AnimController.GetLimb(lb.LimbType); @@ -588,31 +791,84 @@ namespace Barotrauma.Items.Components return false; } - //someone already using the item - if (user != null && !user.Removed) + // Someone already using the item + if (User != null && !User.Removed) { - if (user == activator) + // Let the server handle the logic here + if (GameMain.NetworkMember is { IsClient: true }) { - IsActive = false; - CancelUsing(user); - user = null; return false; } - else if (user.IsBot && !activator.IsBot) + + // Prevent user from kicking character out if they are holding another character + if (AllowPuttingInOtherCharacters && CanPutSelectedCharacter(activator.SelectedCharacter)) + { + return false; + } + + if (User == activator || SelectingKicksCharacterOut) + { +#if SERVER + if (User != activator) + { + GameServer.Log($"{GameServer.CharacterLogName(activator)} removed {GameServer.CharacterLogName(User)} from {item.Name}", + ServerLog.MessageType.Attack); + } +#endif + + IsActive = false; + CancelUsing(User); + User = null; + return false; + } + else if (User.IsBot && !activator.IsBot) { if (AllowSelectingWhenSelectedByBot) { - CancelUsing(user); - user = activator; + CancelUsing(User); + User = activator; IsActive = true; return true; } } return AllowSelectingWhenSelectedByOther; } - else + else if (AllowPuttingInOtherCharacters && CanPutSelectedCharacter(activator.SelectedCharacter)) { - user = activator; + // Stun pets longer so they don't immediately get out of the controller + if (activator.SelectedCharacter.IsPet) + { + activator.SelectedCharacter.SetStun(MathF.Max(activator.SelectedCharacter.Stun, 4f), isNetworkMessage: true); + } + else + { + // Small amount of stun since non-ragdolled characters behave weirdly when syncing the periodic teleportation in multiplayer + activator.SelectedCharacter.SetStun(MathF.Max(activator.SelectedCharacter.Stun, 1f), isNetworkMessage: true); + } + +#if SERVER + GameServer.Log($"{GameServer.CharacterLogName(activator)} forced {GameServer.CharacterLogName(activator.SelectedCharacter)} into {item.Name}", + ServerLog.MessageType.Attack); +#endif + + User = activator.SelectedCharacter; + User.SelectedItem = this.Item; + IsActive = true; + if (ForceUserToStayAttached && item.Container != null) + { + forceSelectNextFrame = true; + } + return false; + } + else if (CanBeSelectedByCharacters) + { +#if SERVER + GameServer.Log($"{GameServer.CharacterLogName(activator)} entered {item.Name}", ServerLog.MessageType.ItemInteraction); +#endif + + activator.DeselectCharacter(); + + User = activator; IsActive = true; if (ForceUserToStayAttached && item.Container != null) { @@ -621,15 +877,12 @@ namespace Barotrauma.Items.Components } } - //allow the selection logic above to run when out of power, but allow sending signals + //allow the selection logic above to run when out of power, but disallow sending signals if (IsOutOfPower()) { return false; } - -#if SERVER - item.CreateServerEvent(this); -#endif + if (!string.IsNullOrEmpty(output)) { - item.SendSignal(new Signal(output, sender: user), "signal_out"); + item.SendSignal(new Signal(output, sender: User), "signal_out"); } return true; } @@ -639,7 +892,7 @@ namespace Barotrauma.Items.Components /// public bool IsAttachedUser(Character character) { - return character != null && character == user && ForceUserToStayAttached; + return character != null && character == User && ForceUserToStayAttached; } public override void FlipX(bool relativeToSub) @@ -668,12 +921,87 @@ namespace Barotrauma.Items.Components } } + public override bool HasRequiredItems(Character character, bool addMessage, LocalizedString msg = null) + { +#if CLIENT + UpdateMsg(); +#endif + + bool canPutCharacter = AllowPuttingInOtherCharacters && CanPutSelectedCharacter(character.SelectedCharacter, addMessage); + bool canKickCharacter = SelectingKicksCharacterOut && User != null && !User.Removed; + bool canUseController = CanBeSelectedByCharacters; + + // Prevent kicking a character out when the user is holding another character to put into the controller. + // This avoids accidentally taking out a character (e.g. from a deconstructor). + if (canPutCharacter && canKickCharacter) + { +#if CLIENT + if (addMessage) + { + GUI.AddMessage(TextManager.Get("ItemMsgAlreadyHasCharacterFail"), Color.Red, playSound: false); + SoundPlayer.PlayUISound(GUISoundType.PickItemFail); + } +#endif + + return false; + } + + if (!canKickCharacter && !canPutCharacter && !canUseController) + { + return false; + } + + if (IsSpawnContainerFull()) + { +#if CLIENT + if (addMessage) + { + GUI.AddMessage(TextManager.Get("ItemMsgNotEnoughSpaceCharacterFail"), Color.Red, playSound: false); + SoundPlayer.PlayUISound(GUISoundType.PickItemFail); + } +#endif + + return false; + } + + return base.HasRequiredItems(character, addMessage, msg); + } + public override bool HasAccess(Character character) { if (!item.IsInteractable(character)) { return false; } return base.HasAccess(character); } + private bool CanPutSelectedCharacter(Character character, bool showMessage = false) + { + if (character == null) + { + return false; + } + + if (!character.IsContainable) + { +#if CLIENT + if (showMessage) + { + GUI.AddMessage(TextManager.Get("ItemMsgPutCharacterFail"), Color.Red); + } +#endif + + return false; + } + + if (character.IsKnockedDownOrRagdolled) { return true; } + if (character.LockHands) { return true; } + if (character.IsPet) + { + return true; + } + + return false; + } + partial void HideHUDs(bool value); public override XElement Save(XElement parentElement) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs index 2ab676500..c6cb73978 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs @@ -114,7 +114,19 @@ namespace Barotrauma.Items.Components float deconstructTime = 0.0f; foreach (Item targetItem in inputContainer.Inventory.AllItems) { - deconstructTime += targetItem.Prefab.DeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier); + float itemDeconstructTime = item.Submarine is { Info.Type: SubmarineType.Outpost } + ? targetItem.Prefab.DeconstructTimeInOutposts : targetItem.Prefab.DeconstructTime; + float targetDeconstructTime = itemDeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier); + + var linkedCharacter = targetItem.GetComponent(); + if (linkedCharacter != null) + { + targetDeconstructTime *= linkedCharacter.DeconstructTimeMultiplier; + } + + deconstructTime += targetDeconstructTime; + + ApplyDeconstructionStatusEffects(targetItem, ActionType.OnDeconstructing, deltaTime); } progressState = Math.Min(progressTimer / deconstructTime, 1.0f); @@ -143,8 +155,21 @@ namespace Barotrauma.Items.Components var targetItem = inputContainer.Inventory.LastOrDefault(); if (targetItem == null) { return; } + ApplyDeconstructionStatusEffects(targetItem, ActionType.OnDeconstructing, deltaTime); + var validDeconstructItems = targetItem.Prefab.DeconstructItems.Where(it => it.IsValidDeconstructor(item)).ToList(); - float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier) : 1.0f; + + float itemDeconstructTime = item.Submarine is { Info.Type: SubmarineType.Outpost } + ? targetItem.Prefab.DeconstructTimeInOutposts : targetItem.Prefab.DeconstructTime; + + float deconstructTime = !targetItem.Prefab.DeconstructItems.Any() || validDeconstructItems.Any() + ? itemDeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier) : 1.0f; + + var linkedCharacter = targetItem.GetComponent(); + if (linkedCharacter != null) + { + deconstructTime *= linkedCharacter.DeconstructTimeMultiplier; + } progressState = Math.Min(progressTimer / deconstructTime, 1.0f); if (progressTimer > deconstructTime) @@ -183,6 +208,8 @@ namespace Barotrauma.Items.Components amountMultiplier = (int)itemCreationMultiplier.Value; } + ApplyDeconstructionStatusEffects(targetItem, ActionType.OnDeconstructed, 1f); + if (targetItem.Prefab.RandomDeconstructionOutput) { int amount = targetItem.Prefab.RandomDeconstructionOutputAmount; @@ -297,30 +324,8 @@ namespace Barotrauma.Items.Components { humanAi.HandleRelocation(spawnedItem); } - for (int i = 0; i < outputContainer.Capacity; i++) - { - var containedItem = outputContainer.Inventory.GetItemAt(i); - bool combined = false; - if (containedItem?.OwnInventory != null) - { - foreach (Item subItem in containedItem.ContainedItems.ToList()) - { - if (subItem.Combine(spawnedItem, null)) - { - combined = true; - break; - } - } - } - if (!combined) - { - if (containedItem?.Combine(spawnedItem, null) ?? false) - { - break; - } - } - } - PutItemsToLinkedContainer(); + + TryMoveItemToOutputContainers(spawnedItem); }); } } @@ -347,6 +352,7 @@ namespace Barotrauma.Items.Components } } } + inputContainer.Inventory.RemoveItem(targetItem); Entity.Spawner.AddItemToRemoveQueue(targetItem); MoveInputQueue(); @@ -381,6 +387,34 @@ namespace Barotrauma.Items.Components } } + private void TryMoveItemToOutputContainers(Item spawnedItem) + { + for (int i = 0; i < outputContainer.Capacity; i++) + { + var containedItem = outputContainer.Inventory.GetItemAt(i); + bool combined = false; + if (containedItem?.OwnInventory != null) + { + foreach (Item subItem in containedItem.ContainedItems.ToList()) + { + if (subItem.Combine(spawnedItem, null)) + { + combined = true; + break; + } + } + } + if (!combined) + { + if (containedItem?.Combine(spawnedItem, null) ?? false) + { + break; + } + } + } + PutItemsToLinkedContainer(); + } + private void PutItemsToLinkedContainer() { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } @@ -399,6 +433,72 @@ namespace Barotrauma.Items.Components } } + private void ApplyDeconstructionStatusEffects(Item targetItem, ActionType type, float deltaTime) + { + var linkedCharacterComponent = targetItem.GetComponent(); + Character character = null; + if (linkedCharacterComponent is { Character.Removed: false }) + { + character = linkedCharacterComponent.Character; + } + + Limb limb = character?.AnimController.Limbs.GetRandomUnsynced(); + + if (user != null) + { + item.GetStatusEffectsOfType(type).ForEach(statusEffect => statusEffect.SetUser(user)); + targetItem.GetStatusEffectsOfType(type).ForEach(statusEffect => statusEffect.SetUser(user)); + } + + // Apply OnDeconstruct/OnDeconstructing to the Deconstructor/item being deconstructed + item.ApplyStatusEffects(type, deltaTime, character, limb, useTarget: targetItem); + targetItem.ApplyStatusEffects(type, deltaTime, character, limb); + + if (character != null) + { + if (type == ActionType.OnDeconstructed) + { + // Move whatever was on the character inventory to free up space for status effects that spawn items + MoveItemsFromCharacterToOutput(); + } + + character.ApplyStatusEffects(type, deltaTime); + + if (type == ActionType.OnDeconstructed) + { + // This needs to run next frame because the status effect might enqueue items to be spawned next frame + CoroutineManager.Invoke(() => + { + if (character.Removed) { return; } + + // Move items again since the status effect could have spawned additional items in the character inventory + MoveItemsFromCharacterToOutput(); + + Entity.Spawner?.AddEntityToRemoveQueue(character); + }, 0.1f); + } + + void MoveItemsFromCharacterToOutput() + { + if (character.Inventory != null) + { + foreach (var item in character.Inventory.AllItemsMod) + { + if (item.Removed) { continue; } + if (!item.IsPlayerTeamInteractable) { continue; } + + if (!outputContainer.Inventory.TryPutItem(item, user: null)) + { + item.Drop(dropper: null); + } + + TryMoveItemToOutputContainers(item); + } + } + } + } + } + /// /// Move items towards the last slot in the inventory if there's free slots /// diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index 52df29696..6676545ae 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -388,6 +388,13 @@ namespace Barotrauma.Items.Components { Attack.DamageMultiplier = damageMultiplier; } + foreach (var statusEffect in Item.GetStatusEffectsOfType(ActionType.OnImpact)) + { + foreach (var explosion in statusEffect.Explosions) + { + explosion.Attack.DamageMultiplier = damageMultiplier; + } + } // Set user for hitscan projectiles to work properly. User = user; // Need to set null for non-characterusable items. @@ -460,6 +467,7 @@ namespace Barotrauma.Items.Components { initialRotation -= MathHelper.Pi; } + Submarine initialSubmarine = item.Submarine; for (int i = 0; i < HitScanCount; i++) { float launchAngle; @@ -476,6 +484,8 @@ namespace Barotrauma.Items.Components Vector2 launchDir = new Vector2((float)Math.Cos(launchAngle), (float)Math.Sin(launchAngle)); Vector2 prevSimpos = item.SimPosition; item.body.SetTransformIgnoreContacts(item.body.SimPosition, launchAngle); + //when launching multiple projectiles, ensure each raycast starts from the same sub + item.Submarine = initialSubmarine; if (Hitscan) { DoHitscan(launchDir); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs index 1aebf8187..6ec4fd5a2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs @@ -448,9 +448,10 @@ namespace Barotrauma.Items.Components UpdateProjSpecific(deltaTime); IsTinkering = false; - if (prevSentConditionValue != (int)item.ConditionPercentage || conditionSignal == null) + int condition = (int)(item.Condition / (item.MaxCondition / item.MaxRepairConditionMultiplier) * 100f); + if (prevSentConditionValue != condition || conditionSignal == null) { - prevSentConditionValue = (int)item.ConditionPercentage; + prevSentConditionValue = condition; conditionSignal = prevSentConditionValue.ToString(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs index e0475bbd5..c9a3cab15 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs @@ -27,6 +27,11 @@ namespace Barotrauma.Items.Components private init => _displayName = value; } + /// + /// Display name ignoring + /// + public LocalizedString DefaultDisplayName => _displayName; + public LocalizedString DisplayNameOverride; private readonly HashSet wires; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs index e0104a213..bccb65f42 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs @@ -296,6 +296,7 @@ namespace Barotrauma.Items.Components } #endif CheckIfNeedsUpdate(); + SetLightSourceTransformProjSpecific(); } public void CheckIfNeedsUpdate() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs index d5d7678c5..9da0bcfba 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs @@ -42,6 +42,10 @@ namespace Barotrauma.Items.Components private float currentChargeTime; private bool tryingToCharge; + private const float LineOfSightCheckInterval = 0.5f; + private (Body WorldTarget, Body TransformedTarget, double Time) lastLineOfSightCheck; + private (Character Target, bool CanSee, double Time) lastCanSeeTargetCheck; + private enum ChargingState { Inactive, @@ -1088,6 +1092,7 @@ namespace Barotrauma.Items.Components foreach (Submarine sub in Submarine.Loaded) { if (sub == Item.Submarine) { continue; } + if (sub.IsRespawnShuttle) { continue; } if (item.Submarine != null) { if (Character.IsOnFriendlyTeam(item.Submarine.TeamID, sub.TeamID)) { continue; } @@ -1164,15 +1169,28 @@ namespace Barotrauma.Items.Components } Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition); Vector2 end = ConvertUnits.ToSimUnits(target.WorldPosition); + + bool doLineOfSightCheck = lastLineOfSightCheck.Time < Timing.TotalTimeUnpaused - LineOfSightCheckInterval; + if (doLineOfSightCheck) + { + lastLineOfSightCheck.WorldTarget = CheckLineOfSight(start, end); + lastLineOfSightCheck.Time = Timing.TotalTime; + } + // Check that there's not other entities that shouldn't be targeted (like a friendly sub) between us and the target. - Body worldTarget = CheckLineOfSight(start, end); + Body worldTarget = lastLineOfSightCheck.WorldTarget; bool shoot; if (target.Submarine != null) { - start -= target.Submarine.SimPosition; - end -= target.Submarine.SimPosition; - Body transformedTarget = CheckLineOfSight(start, end); - shoot = CanShoot(transformedTarget, user: null, friendlyTag, TargetSubmarines) && (worldTarget == null || CanShoot(worldTarget, user: null, friendlyTag, TargetSubmarines)); + if (doLineOfSightCheck) + { + start -= target.Submarine.SimPosition; + end -= target.Submarine.SimPosition; + lastLineOfSightCheck.TransformedTarget = CheckLineOfSight(start, end); + } + shoot = + (worldTarget == null || CanShoot(worldTarget, user: null, friendlyTag, TargetSubmarines)) && + CanShoot(lastLineOfSightCheck.TransformedTarget, user: null, friendlyTag, TargetSubmarines); } else { @@ -1437,8 +1455,20 @@ namespace Barotrauma.Items.Components // Adjust the target character position (limb or submarine) if (currentTarget is Character targetCharacter) { + bool enemyInAnotherSub = targetCharacter.Submarine != null && targetCharacter.CurrentHull != null && targetCharacter.Submarine != item.Submarine; + bool canSeeTarget = true; + if (enemyInAnotherSub) + { + if (lastCanSeeTargetCheck.Time < Timing.TotalTime - LineOfSightCheckInterval || + targetCharacter != lastCanSeeTargetCheck.Target) + { + canSeeTarget = targetCharacter.CanSeeTarget(Item); + lastCanSeeTargetCheck = (targetCharacter, canSeeTarget, Timing.TotalTime); + } + } + //if the enemy is inside another sub, aim at the room they're in to make it less obvious that the enemy "knows" exactly where the target is - if (targetCharacter.Submarine != null && targetCharacter.CurrentHull != null && targetCharacter.Submarine != item.Submarine && !targetCharacter.CanSeeTarget(Item)) + if (enemyInAnotherSub && !canSeeTarget) { targetPos = targetCharacter.CurrentHull.WorldPosition; if (closestDistance > maxDistance * maxDistance) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs index ce4da3bda..54c9a5f90 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs @@ -569,16 +569,16 @@ namespace Barotrauma /// /// If there is room, puts the item in the inventory and returns true, otherwise returns false /// - public virtual bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false) + public virtual bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { int slot = FindAllowedSlot(item, ignoreCondition); if (slot < 0) { return false; } - PutItem(item, slot, user, true, createNetworkEvent); + PutItem(item, slot, user, true, createNetworkEvent, triggerOnInsertedEffects); return true; } - public virtual bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false) + public virtual bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { if (!IsIndexInRange(i)) { @@ -609,14 +609,14 @@ namespace Barotrauma //item in the slot removed as a result of combining -> put this item in the now free slot if (!slots[i].Any()) { - return TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent, ignoreCondition); + return TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent, ignoreCondition, triggerOnInsertedEffects); } return true; } } if (CanBePutInSlot(item, i, ignoreCondition)) { - PutItem(item, i, user, true, createNetworkEvent); + PutItem(item, i, user, true, createNetworkEvent, triggerOnInsertedEffects); return true; } else if (slots[i].Any() && item.ParentInventory != null && allowSwapping) @@ -642,7 +642,7 @@ namespace Barotrauma } } - protected virtual void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true) + protected virtual void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true, bool triggerOnInsertedEffects = true) { if (!IsIndexInRange(i)) { @@ -941,7 +941,8 @@ namespace Barotrauma { foreach (var item in items) { - if (!inventory.TryPutItem(item, slotIndex, false, false, user, createNetworkEvent, ignoreCondition: true) && + //don't trigger OnInserted effects: we're not really "inserting" but just putting it back where it was because swapping failed + if (!inventory.TryPutItem(item, slotIndex, false, false, user, createNetworkEvent, ignoreCondition: true, triggerOnInsertedEffects: false) && !inventory.GetItemsAt(slotIndex).Contains(item)) { inventory.ForceToSlot(item, slotIndex); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 53d7e0faf..41f69d22f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -262,6 +262,8 @@ namespace Barotrauma /// public Character Equipper; + public Inventory PreviousParentInventory { get; set; } + //the inventory in which the item is contained in public Inventory ParentInventory { @@ -277,9 +279,7 @@ namespace Barotrauma Container = parentInventory.Owner as Item; RemoveFromDroppedStack(allowClientExecute: false); } -#if SERVER PreviousParentInventory = value; -#endif } } @@ -560,6 +560,8 @@ namespace Barotrauma set; } = float.PositiveInfinity; + public Sprite OverrideInventorySprite { get; set; } + protected Color spriteColor; [Editable, Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.Yes)] public Color SpriteColor @@ -1102,7 +1104,7 @@ namespace Barotrauma public override string ToString() { - return Name + " (ID: " + ID + ")"; + return (Name.IsNullOrEmpty() ? Prefab.Identifier : Name) + " (ID: " + ID + ")"; } private readonly List allPropertyObjects = new List(); @@ -1790,7 +1792,8 @@ namespace Barotrauma ic.Move(amount, ignoreContacts); } - if (body != null && (Submarine == null || !Submarine.Loading) || Screen.Selected is { IsEditor: true }) { FindHull(); } + // Refresh items without a body in editors so vents (or other static items that do something with hulls) know which hull they are in after being moved + if ((body != null || Screen.Selected is { IsEditor: true }) && Submarine is not { Loading: true }) { FindHull(); } } public Rectangle TransformTrigger(Rectangle trigger, bool world = false) @@ -2070,6 +2073,12 @@ namespace Barotrauma } } + public IEnumerable GetStatusEffectsOfType(ActionType type) + { + if (!hasStatusEffectsOfType[(int)type]) { return Enumerable.Empty(); } + return statusEffectLists[type]; + } + /// /// Executes all StatusEffects of the specified type. Note that condition checks are ignored here: that should be handled by the code calling the method. /// @@ -3255,7 +3264,9 @@ namespace Barotrauma bool showUiMsg = false; #if CLIENT if (!ic.HasRequiredSkills(user, out Skill tempRequiredSkill)) { hasRequiredSkills = false; skillMultiplier = ic.GetSkillMultiplier(); } - showUiMsg = user == Character.Controlled && Screen.Selected != GameMain.SubEditorScreen; + showUiMsg = user == Character.Controlled && Screen.Selected != GameMain.SubEditorScreen && + // Only show the UI message of the component that we actually want to interact with + (pickHit && ic.CanBePicked || selectHit && ic.CanBeSelected); #endif if (!ignoreRequiredItems && !ic.HasRequiredItems(user, showUiMsg)) { continue; } if ((ic.CanBePicked && pickHit && ic.Pick(user)) || @@ -4354,6 +4365,9 @@ namespace Barotrauma Rotation = Rotation }; + if (FlippedX) { newItem.FlipX(relativeToSub: false); } + if (FlippedY) { newItem.FlipY(relativeToSub: false); } + float scaleRelativeToPrefab = Scale / Prefab.Scale; newItem.Scale *= scaleRelativeToPrefab; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs index 1a8cf3cc1..29b914960 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs @@ -88,9 +88,9 @@ namespace Barotrauma return true; } - public override bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false) + public override bool TryPutItem(Item item, Character user, IEnumerable allowedSlots = null, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { - bool wasPut = base.TryPutItem(item, user, allowedSlots, createNetworkEvent, ignoreCondition); + bool wasPut = base.TryPutItem(item, user, allowedSlots, createNetworkEvent, ignoreCondition, triggerOnInsertedEffects); if (wasPut) { @@ -111,9 +111,9 @@ namespace Barotrauma return wasPut; } - public override bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false) + public override bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true, bool ignoreCondition = false, bool triggerOnInsertedEffects = true) { - bool wasPut = base.TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent, ignoreCondition); + bool wasPut = base.TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent, ignoreCondition, triggerOnInsertedEffects); if (wasPut && item.ParentInventory == this) { foreach (Character c in Character.CharacterList) @@ -124,7 +124,7 @@ namespace Barotrauma } container.IsActive = true; - container.OnItemContained(item); + container.OnItemContained(item, triggerOnInsertedEffects); #if SERVER GameMain.Server?.KarmaManager?.OnItemContained(item, container.Item, user); #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index c340efab6..a52d1d94c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -548,6 +548,8 @@ namespace Barotrauma public float DeconstructTime { get; private set; } + public float DeconstructTimeInOutposts { get; private set; } + public bool AllowDeconstruct { get; private set; } //Containers (by identifiers or tags) that this item should be placed in. These are preferences, which are not enforced. @@ -1074,6 +1076,7 @@ namespace Barotrauma var storePrices = new Dictionary(); var preferredContainers = new List(); DeconstructTime = 1.0f; + DeconstructTimeInOutposts = DeconstructTime; if (ConfigElement.GetAttribute("allowasextracargo") != null) { @@ -1174,6 +1177,7 @@ namespace Barotrauma break; case "deconstruct": DeconstructTime = subElement.GetAttributeFloat("time", 1.0f); + DeconstructTimeInOutposts = subElement.GetAttributeFloat("timeinoutposts", DeconstructTime); AllowDeconstruct = true; RandomDeconstructionOutput = subElement.GetAttributeBool("chooserandom", false); RandomDeconstructionOutputAmount = subElement.GetAttributeInt("amount", 1); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs index 2bb9cb587..cad423406 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs @@ -398,7 +398,7 @@ namespace Barotrauma } foreach (Item contained in container.Inventory.AllItems) { - if (TargetSlot > -1 && parentItem.OwnInventory.FindIndex(contained) != TargetSlot) { continue; } + if (TargetSlot > -1 && container.Inventory.FindIndex(contained) != TargetSlot) { continue; } if ((!ExcludeBroken || contained.Condition > 0.0f) && (!ExcludeFullCondition || !contained.IsFullCondition) && MatchesItem(contained)) { return true; } if (CheckContained(contained)) { return true; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs index 1c193d983..7c4391e1f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Hull.cs @@ -123,6 +123,8 @@ namespace Barotrauma public const float OxygenDeteriorationSpeed = 0.3f; public const float OxygenConsumptionSpeed = 700.0f; + private const float DecalAlphaRemoveThreshold = 0.001f; + public const int WaveWidth = 32; public static float WaveStiffness = 0.01f; public static float WaveSpread = 0.02f; @@ -913,7 +915,7 @@ namespace Barotrauma for (int i = decals.Count - 1; i >= 0; i--) { var decal = decals[i]; - if (decal.FadeTimer >= decal.LifeTime || decal.BaseAlpha <= 0.001f) + if (decal.FadeTimer >= decal.LifeTime || decal.BaseAlpha <= DecalAlphaRemoveThreshold) { decals.RemoveAt(i); #if SERVER @@ -1159,7 +1161,10 @@ namespace Barotrauma Hull currentHull = current.hull; Vector2 currentPos = current.pos; - if (currentDist > maxDistance) { return float.MaxValue; } + if (currentDist > maxDistance) + { + return float.MaxValue; + } // If we've reached the target, add the final segment from hull to endPos if (currentHull == targetHull) @@ -1167,7 +1172,7 @@ namespace Barotrauma return currentDist + Vector2.Distance(currentPos, endPos); } - foreach (Gap g in ConnectedGaps) + foreach (Gap g in currentHull.ConnectedGaps) { float distanceMultiplier = 1; if (g.ConnectedDoor != null && !g.ConnectedDoor.IsBroken) @@ -1643,9 +1648,18 @@ namespace Barotrauma bool decalsCleaned = false; foreach (Decal decal in decals) { + // Don't attempt to clean the decal if it's already below the remove threshold, since the server + // is already gonna remove the decal for us, sending another decal update event would result in + // us potentially modifying a different decal since the indices can briefly desync. + if (decal.BaseAlpha <= DecalAlphaRemoveThreshold) + { + continue; + } + if (decal.AffectsSection(section)) { decal.Clean(cleanVal); + decalsCleaned = true; #if SERVER decalUpdatePending = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index c5f0d161f..71f4b0752 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -7,6 +7,7 @@ using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -327,6 +328,7 @@ namespace Barotrauma public Submarine BeaconStation { get; private set; } private Sonar beaconSonar; + private ImmutableArray beaconTransducers = ImmutableArray.Empty; /// /// Special wall chunks that aren't part of the normal level geometry: includes things like the ocean floor, floating ice chunks and ice spires. @@ -4398,6 +4400,13 @@ namespace Barotrauma attempts++; } } + + foreach (var wreck in Wrecks) + { + wreck.SetCrushDepth(wreck.RealWorldDepth + 1000); + SetLinkedSubCrushDepth(wreck); + } + totalSW.Stop(); Debug.WriteLine($"{Wrecks.Count} wrecks created in { totalSW.ElapsedMilliseconds} (ms)"); } @@ -4782,6 +4791,7 @@ namespace Barotrauma return; } beaconSonar = sonarItem.GetComponent(); + beaconTransducers = sonarItem.GetConnectedComponents().ToImmutableArray(); } public void PrepareBeaconStation() @@ -4908,9 +4918,20 @@ namespace Barotrauma public bool CheckBeaconActive() { if (beaconSonar == null) { return false; } + if (beaconSonar.UseTransducers) + { + var connectedTransducers = beaconSonar.Item.GetConnectedComponents(); + foreach (var beaconTransducer in beaconTransducers) + { + if (!beaconTransducer.HasPower || !connectedTransducers.Contains(beaconTransducer)) { return false; } + } + } return beaconSonar.HasPower && beaconSonar.CurrentMode == Sonar.Mode.Active; } + /// + /// Set the crush depths of the connected subs to match the crush depth of the parent sub. + /// private void SetLinkedSubCrushDepth(Submarine parentSub) { foreach (var connectedSub in parentSub.GetConnectedSubs()) @@ -5149,6 +5170,7 @@ namespace Barotrauma BeaconStation = null; beaconSonar = null; + beaconTransducers = ImmutableArray.Empty; StartOutpost = null; EndOutpost = null; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs index 03e37859c..b7460e61c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs @@ -413,8 +413,7 @@ namespace Barotrauma new XAttribute("difficulty", Difficulty.ToString("G", CultureInfo.InvariantCulture)), new XAttribute("size", XMLExtensions.PointToString(Size)), new XAttribute("generationparams", GenerationParams.Identifier), - new XAttribute("initialdepth", InitialDepth), - new XAttribute("exhaustedeventsets", allEventsExhausted)); + new XAttribute("initialdepth", InitialDepth)); newElement.Add( new XAttribute(nameof(exhaustedEventSets), string.Join(',', exhaustedEventSets.Select(e => e.Value)))); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs index 8339e6c65..b96b7f1a7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs @@ -651,7 +651,7 @@ namespace Barotrauma newBody.Friction = 0.8f; newBody.UserData = this; - newBody.Position = ConvertUnits.ToSimUnits(stairPos) + BodyOffset * Scale; + newBody.Position = ConvertUnits.ToSimUnits(stairPos) + ConvertUnits.ToSimUnits(BodyOffset) * Scale; bodyDimensions.Add(newBody, new Vector2(bodyWidth, bodyHeight)); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs index 1dc9d991c..10c1728ae 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs @@ -583,7 +583,11 @@ namespace Barotrauma { for (int dir = -1; dir <= 1; dir += 2) { - WayPoint closest = stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(minDist * 1.5f, minDist / 2)); + //connect to the closest waypoint, preferring non-stair waypoyints + //(it's easier for characters to fully get off stairs before moving on to the next set of stairs, than to move directly from one set of stairs to another) + WayPoint closest = + stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(minDist * 1.5f, minDist / 2), filter: wp => wp.Stairs == null) ?? + stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(minDist * 1.5f, minDist / 2)); if (closest == null) { continue; } stairPoints[i].ConnectTo(closest); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetConfig.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetConfig.cs index 38e335927..efb3d7916 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetConfig.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetConfig.cs @@ -39,6 +39,12 @@ namespace Barotrauma.Networking public const int MaxEventPacketsPerUpdate = 4; + /// + /// When enabled, uses more lenient Lidgren handshake timeouts (longer connection timeout, more retry attempts). + /// Useful for local testing when running multiple instances on the same machine under heavy load. + /// + public static bool UseLenientHandshake; + /// /// Interpolates the positional error of a physics body towards zero. /// diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetIdUtils.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetIdUtils.cs index e75202086..54f671521 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetIdUtils.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetIdUtils.cs @@ -33,13 +33,7 @@ namespace Barotrauma.Networking /// regarding its relation to values other than the input. /// public static ushort GetIdOlderThan(ushort id) -#if DEBUG - // Debug implementation has some RNG to discourage bad assumptions about the return value - => unchecked((ushort)(id - 1 - Rand.Int(500, sync: Rand.RandSync.Unsynced))); -#else - // Release implementation favors performance => unchecked((ushort)(id - 1)); -#endif public static ushort Difference(ushort id1, ushort id2) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Auth/SteamAuthTicketForEosHostAuthenticator.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Auth/SteamAuthTicketForEosHostAuthenticator.cs index ff2788158..aa2d46143 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Auth/SteamAuthTicketForEosHostAuthenticator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Auth/SteamAuthTicketForEosHostAuthenticator.cs @@ -15,13 +15,18 @@ sealed class SteamAuthTicketForEosHostAuthenticator : Authenticator { string ticketData = ToolBoxCore.ByteArrayToHexString(ticket.Data); - var client = new RestClient(ServerUrl); - - var request = new RestRequest(ServerFile, Method.GET); + var client = RestFactory.CreateClient(ServerUrl); + var request = RestFactory.CreateRequest(ServerFile); request.AddParameter("authticket", ticketData); request.AddParameter("request_version", RemoteRequestVersion); var response = await client.ExecuteAsync(request, Method.GET); + if (response.ErrorException != null) + { + DebugConsole.AddWarning($"Connection error: Failed to verify Steam auth ticket for EOS host " + + $"({response.ErrorException.Message})."); + return AccountInfo.None; + } if (!response.IsSuccessful) { return AccountInfo.None; } try diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerSettings.cs index 89a84fbfe..696b70a0d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerSettings.cs @@ -454,7 +454,7 @@ namespace Barotrauma.Networking private set; } - [Serialize(300.0f, IsPropertySaveable.Yes)] + [Serialize(30.0f, IsPropertySaveable.Yes)] public float RespawnInterval { get; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs index 58f0f5280..5434b25a5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Physics/PhysicsBody.cs @@ -534,8 +534,10 @@ namespace Barotrauma default: throw new NotImplementedException(); } - return spritesheetRotation.HasValue ? Vector2.Transform(pos, Matrix.CreateRotationZ(-spritesheetRotation.Value)) : pos; + return spritesheetRotation.HasValue ? RotateVector(pos, spritesheetRotation.Value) : pos; } + + public static Vector2 RotateVector(Vector2 v, float rotation) => Vector2.Transform(v, Matrix.CreateRotationZ(-rotation)); public float GetMaxExtent() { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabCollection.cs b/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabCollection.cs index 47b575be5..f3a0a4842 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabCollection.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabCollection.cs @@ -410,7 +410,7 @@ namespace Barotrauma && otherPrefab.UintIdentifier == prefabWithUintIdentifier.UintIdentifier); for (T? collision = findCollision(); collision != null; collision = findCollision()) { - DebugConsole.ThrowError($"Hashing collision when generating uint identifiers for {typeof(T).Name}: {prefab.Identifier} has the same UintIdentifier as {collision.Identifier} ({prefabWithUintIdentifier.UintIdentifier})"); + DebugConsole.AddWarning($"Hashing collision when generating uint identifiers for {typeof(T).Name}: {prefab.Identifier} has the same UintIdentifier as {collision.Identifier} ({prefabWithUintIdentifier.UintIdentifier})"); prefabWithUintIdentifier.UintIdentifier++; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs index b04914057..a3a19cddb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs @@ -36,6 +36,27 @@ namespace Barotrauma { typeof(Rectangle), (str, defVal) => ParseRect(str, true) } }.ToImmutableDictionary(); + /// + /// Check if the given value equals to the default value of the property. + /// Takes into account that certain default values (e.g. Vectors and other values that aren't compile-time constants) are defined as strings. + /// + public static bool DefaultValueEquals(object defaultValue, object value) + { + //if the value is given as a string, check if there's a converter for the type of the default value and attempt converting + if (defaultValue != null && value is string valueAsString && + Converters.TryGetKey(defaultValue.GetType(), out Type type)) + { + return Equals(Converters[type].Invoke(valueAsString, defaultValue), defaultValue); + } + //other way around: default values is given as a string, check if there's a converter for the type of the value + else if (value != null && defaultValue is string defaultValueAsString && + Converters.TryGetKey(value.GetType(), out Type type2)) + { + return Equals(Converters[type2].Invoke(defaultValueAsString, value), value); + } + return Equals(value, defaultValue); + } + public static string ParseContentPathFromUri(this XObject element) => !string.IsNullOrWhiteSpace(element.BaseUri) ? System.IO.Path.GetRelativePath(Environment.CurrentDirectory, element.BaseUri.CleanUpPath()) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs index eb44f9d6b..8f22a4da0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs @@ -72,6 +72,7 @@ namespace Barotrauma EnableSplashScreen = true, PauseOnFocusLost = true, RemoteMainMenuContentUrl = "https://www.barotraumagame.com/gamedata/", + RemoteContentTimeoutSeconds = 15f, AimAssistAmount = DefaultAimAssist, ShowEnemyHealthBars = EnemyHealthBarMode.ShowAll, ChatSpeechBubbles = true, @@ -167,6 +168,17 @@ namespace Barotrauma public bool EnableSubmarineAutoSave; public Identifier QuickStartSub; public string RemoteMainMenuContentUrl; + + /// + /// Timeout in seconds for HTTP requests to remote content servers. + /// + public float RemoteContentTimeoutSeconds; + + /// + /// Returns converted to milliseconds needed by eg. RestSharp. + /// + public readonly int RemoteContentTimeoutMs => (int)(RemoteContentTimeoutSeconds * 1000); + #if CLIENT public Eos.EosSteamPrimaryLogin.CrossplayChoice CrossplayChoice; public XElement SavedCampaignSettings; diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index bdd8bfac5..2fc581c16 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -841,6 +841,12 @@ namespace Barotrauma /// public Vector2 Offset { get; private set; } + /// + /// Should be rotated, flipped and scaled based on the entity that this effect is executed by? + /// Currently only supports status effects in items. + /// + public bool OffsetCopiesEntityTransform { get; private set; } + /// /// An random offset (in a random direction) added to the position of the effect is executed at. Only relevant if the effect does something where position matters, /// for example emitting particles or explosions, spawning something or playing sounds. @@ -901,6 +907,7 @@ namespace Barotrauma Range = element.GetAttributeFloat("range", 0.0f); Offset = element.GetAttributeVector2("offset", Vector2.Zero); + OffsetCopiesEntityTransform = element.GetAttributeBool(nameof(OffsetCopiesEntityTransform), false); RandomOffset = element.GetAttributeFloat("randomoffset", 0.0f); string[] targetLimbNames = element.GetAttributeStringArray("targetlimb", null) ?? element.GetAttributeStringArray("targetlimbs", null); if (targetLimbNames != null) @@ -1724,6 +1731,7 @@ namespace Barotrauma protected Vector2 GetPosition(Entity entity, IReadOnlyList targets, Vector2? worldPosition = null) { Vector2 position = worldPosition ?? (entity == null || entity.Removed ? Vector2.Zero : entity.WorldPosition); + if (worldPosition == null) { if (entity is Character character && !character.Removed && targetLimbs != null) @@ -1760,9 +1768,22 @@ namespace Barotrauma } } } - } - position += Offset; + + Vector2 offset = Offset; + + if (OffsetCopiesEntityTransform) + { + if (entity is Item item) + { + offset *= item.Scale; + if (item.FlippedX) { offset.X *= -1; } + if (item.FlippedY) { offset.Y *= -1; } + offset = Vector2.Transform(offset, Matrix.CreateRotationZ(-item.RotationRad)); + } + } + + position += offset; position += Rand.Vector(Rand.Range(0.0f, RandomOffset)); return position; } @@ -2060,24 +2081,9 @@ namespace Barotrauma { LocalizedString messageToSay = TextManager.Get(forceSayIdentifier).Fallback(forceSayIdentifier.Value); - if (!messageToSay.IsNullOrEmpty() && target is Character targetCharacter && targetCharacter.SpeechImpediment < 100.0f && !targetCharacter.IsDead) + if (!messageToSay.IsNullOrEmpty() && target is Character targetCharacter) { - ChatMessageType messageType = ChatMessageType.Default; - bool canUseRadio = ChatMessage.CanUseRadio(targetCharacter, out WifiComponent radio); - if (canUseRadio && forceSayInRadio) - { - messageType = ChatMessageType.Radio; - } -#if SERVER - GameMain.Server?.SendChatMessage(messageToSay.Value, messageType, senderClient: null, targetCharacter); -#elif CLIENT - //no need to create the message when playing as a client, the server will send it to us - if (isNotClient) - { - AIChatMessage message = new AIChatMessage(messageToSay.Value, messageType); - targetCharacter.SendSinglePlayerMessage(message, canUseRadio, radio); - } -#endif + targetCharacter.ForceSay(messageToSay, forceSayInRadio); } } @@ -2229,7 +2235,10 @@ namespace Barotrauma inheritedTeam = entity switch { Character c => c.TeamID, - Item it => it.GetRootInventoryOwner() is Character owner ? owner.TeamID : GetTeamFromSubmarine(it), + Item it => + (it.GetRootInventoryOwner() as Character ?? it.PreviousParentInventory?.Owner as Character) is { } owner ? + owner.TeamID : + GetTeamFromSubmarine(it), MapEntity e => GetTeamFromSubmarine(e), _ => null // Default to Team1, when we can't deduce the team (for example when spawning outside the sub AND character inventory). diff --git a/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/TrimLString.cs b/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/TrimLString.cs index 92c987b9e..4eca59969 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/TrimLString.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/TrimLString.cs @@ -9,19 +9,21 @@ namespace Barotrauma public enum Mode { Start = 0x1, End = 0x2, Both=0x3 } private readonly LocalizedString nestedStr; private readonly Mode mode; + private readonly char[]? trimCharacters; - public TrimLString(LocalizedString nestedStr, Mode mode) + public TrimLString(LocalizedString nestedStr, Mode mode, char[]? trimCharacters = null) { this.nestedStr = nestedStr; this.mode = mode; + this.trimCharacters = trimCharacters; } public override bool Loaded => nestedStr.Loaded; public override void RetrieveValue() { cachedValue = nestedStr.Value; - if (mode.HasFlag(Mode.Start)) { cachedValue = cachedValue.TrimStart(); } - if (mode.HasFlag(Mode.End)) { cachedValue = cachedValue.TrimEnd(); } + if (mode.HasFlag(Mode.Start)) { cachedValue = cachedValue.TrimStart(trimCharacters); } + if (mode.HasFlag(Mode.End)) { cachedValue = cachedValue.TrimEnd(trimCharacters); } UpdateLanguage(); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Text/TextPack.cs b/Barotrauma/BarotraumaShared/SharedSource/Text/TextPack.cs index 19ee41a2f..5ba27c155 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Text/TextPack.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Text/TextPack.cs @@ -242,7 +242,10 @@ namespace Barotrauma } - Barotrauma.IO.File.WriteAllText($"csv_{Language.ToString().ToLower()}_{index}.csv", sb.ToString()); + string fileName = $"csv_{Language.ToString().ToLower()}_{index}.csv"; + Barotrauma.IO.File.WriteAllText(fileName, sb.ToString()); + + DebugConsole.NewMessage($"Wrote \"{ContentFile.Path}\" to \"{fileName}\""); } #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/RestFactory.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/RestFactory.cs new file mode 100644 index 000000000..1c3c38f97 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/RestFactory.cs @@ -0,0 +1,35 @@ +using RestSharp; + +namespace Barotrauma +{ + /// + /// Factory methods for creating RestSharp clients and requests with default timeout + /// settings, to avoid unforeseen connectivity issues hanging the game. + /// The timeout needs to be added to both the client and the request, due to known + /// issues with RestSharp 106.x that we use: https://github.com/restsharp/RestSharp/issues/1900 + /// + public static class RestFactory + { + /// + /// Creates a RestClient with applied. + /// + public static RestClient CreateClient(string baseUrl) + { + return new RestClient(baseUrl) + { + Timeout = GameSettings.CurrentConfig.RemoteContentTimeoutMs + }; + } + + /// + /// Creates a RestRequest with applied. + /// + public static RestRequest CreateRequest(string resource, Method method = Method.GET) + { + return new RestRequest(resource, method) + { + Timeout = GameSettings.CurrentConfig.RemoteContentTimeoutMs + }; + } + } +} diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index fcd1b5730..3c6b19da0 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,4 +1,94 @@ ------------------------------------------------------------------------------------------------------------------------------------------------- +v1.12.6.2 +------------------------------------------------------------------------------------------------------------------------------------------------- + +- Updated localization files. + +------------------------------------------------------------------------------------------------------------------------------------------------- +v1.12.6.1 +------------------------------------------------------------------------------------------------------------------------------------------------- + +- Fixed some conversation prompts (such as the one with Artie Dolittle) being misaligned, causing parts the text to be cropped. More specifically, ones that start with some special event sprite but also show the speaker's face in the prompt. +- Fixed pets having trouble moving due to some of the navigation changes in the previous build. Also caused huskified containers to get launched off with enormous speed when they tried to eat something. +- Fixed navigation terminals in shuttles having their maintain position get messed up between level transitions. + +------------------------------------------------------------------------------------------------------------------------------------------------- +v1.12.6.0 (Spring Update 2026) +------------------------------------------------------------------------------------------------------------------------------------------------- + +Submarine reworks: +- Tier 1 submarines (Barsuk, Dugong, Orca and Camel) have all received a visual polish as well as gameplay polishing. +- Camel and Orca now uses the pipe weakpoints and valves system. +- Various improvements and additions to the vanilla item assemblies. + +Balance: +- Increase health of flare, alienflare and glowstick. Now doesn't get destroyed as quickly by monsters, allowing it be a more useful distraction again. Glowsticks don't aggro monsters from as far as flares. +- Sonar Beacon's sound range is reduced, and when dropped can now be destroyed by monsters (to avoid making flares redundant due to being a better and invulnerable version of monster distraction). + +Changes: +- Characters can now be "deconstructed" by dragging them into a deconstructor, producing small amounts of raw materials. Also a handy way to get rid of monster corpses on the submarine, and perhaps problematic crew mates as well. +- Stationary batteries can charge the battery cells inside them even when the output is disabled. +- A handful of missions in which you can earn a reward for getting through the level fast enough (which also serve as an example of the new custom mission functionality, see the Modding section for more information). +- Minor lighting optimizations. + +Multiplayer: +- Reduced the default respawn interval from 300 seconds to 30. +- Fixed an issue that sometimes caused the list of hidden subs to get out of sync in multiplayer, preventing some subs from being purchased. +- Fixed pickup sound not playing when picking up an item in multiplayer. +- Fixed karma system considering bandages and other medical items "dangerous" and giving a penalty for taking them from other players. +- Characters no longer drop items when the player disconnects (meaning you won't lose the items you were holding). + +Fixes: +- Another attempt to fix reported freezes at 80% in the loading screen, which seems to have been caused by Steam's servers or our master server refusing connection attempts from certain kinds of IPs, causing the game to hang waiting for the connection. +- Fixed conversation/event prompts sometimes getting stuck when you went rapidly pressing E. In particular, this happened with events that allow you to retrigger the same event by interacting with the NPC again. +- Fixed certain monsters (e.g. mudraptors) having trouble dropping through hatches inside the sub. +- Fixed monsters often failing to follow targets from sub to another (e.g. from Remora's drone to the main sub). +- Fixes to pathfinding bugs that sometimes caused bots to get stuck on stairs. +- Fixed closing the health interface while your cursor is on another character opening that character's health interface. +- Fixed an AI bug that often prevented outpost NPCs from putting out fires. +- Fixed projectiles that fire more than one raycast per shot (e.g. shotgun shells) only registering one hit if you're firing from inside to outside. +- Fixed implacable sometimes not triggering in time, causing a 5-second stun when vitality dropped below zero. +- Fixed radio jammer not having the traitormissionitem tag (unlike every other traitor mission item). +- Fixed ruin scan missions sometimes failing to choose all 3 positions to scan, making the mission impossible to complete. Happened with very small ruins in particular. +- Fixed Engineering_G4 module sometimes spawning with a ladder leading nowhere. +- Hide items inside non-interactable containers (e.g. decorative items not accessible to the player) showing up on the item finder. +- The achievement for killing a monster is also awarded if the monster is killed by an bot in single player. +- Fixed some items sometimes teleporting to the origin when saving and loading in the submarine editor. +- Fixed a broken waypoint near Berilia's engine which made bots sometimes get stuck there. +- Fixed shuttles/drones/elevators or other parts of a wreck getting crush depth damage in deep levels. +- Characters that respawn in a flooded hull (in either a submarine or an outpost) now spawn with diving gear. +- Fixed fabrication tooltip being unclear (previously showed "requires recipe to fabricate" in red even when the recipe is already learnt, now shows in green that is has been learned) +- Fixed characters sometimes not taking fall damage if they fall on a mirrored structure. +- Fixed portable pumps getting damaged by explosions, despite not being repairable. +- Fixed pet raptors getting assigned an incorrect team if they hatch in a hostile outpost. +- Fixed Linux systems failing to load content packages whose filelist.xml files aren't all lower-case. +- Fixed NPCs ignoring infected humans attacking them. +- Fixed mirrored items becoming unmirrored when swapped by perk points (e.g. a mirrored periscope base becoming an unmirrored periscope when purchasing a turret with a perk point). +- Fixed inability to rename already-hired bots if you no longer have the required reputation to hire the bot. +- Fixed WeaponDamageModifier (a multiplier in RangedWeapon which seems to be used for buffing the damage of variants of a weapon) not affecting explosion damage. Means that e.g. Harpoon-Coil Rifle or Autoshotgun's modifiers don't actually do much when using explosive ammo. +- Fixed creatures not being able to "properly leave a sub" if any of their severed limbs are still inside the sub. In practice, they'd still be considered to be inside the sub, and they would not collide with anything outside it. +- Fixed toggling layer visibility selecting that layer in the sub editor. +- Fixed pasting entities unhiding all of the layers in the sub editor. +- Fixed condition_out connections not taking into account the multipliers applied by the Tinkerer talent. +- Fixed bots still refusing to deconstruct items that yield nothing, even though you could order them to deconstruct those. + +Modding: +- Support for custom event-based missions. The mission simply triggers a specific event, and that event can control the success/failure of the mission using MissionStateAction. See the "TimeTrial" missions in Missions.xml for an usage example. +- Character, level and particle editors show fields set to the default values as gray. Makes it easier to tell which fields have been modified or are relevant for that specific character/level/particle. +- It's possible to add empty RequiredItem elements to item components to make them not have any requirements by default, but allowing them to be added in the submarine editor. +- Fixed limb's randomcolor attribute not working as expected: every character of the same type would get the same randomly chosen color, instead of a different color being chosen for each character. +- Added ForceSayAction which can be used by scripted events to make characters speak in the chat. ConversationAction can also now be used to display text in the chat in addition to the conversation prompt. +- CheckConditionalAction now fails instead of succeeding if it can't find the specified target. There's also a property called FailIfTargetNotFound to make it succeed instead. +- CountTargetsAction now fails instead of succeeding if it's trying to compare against the amount of some other target (e.g. "number of flooded hulls" is at least 30% of the "number of all hulls") and none of that other target can't be found. +- Fixed light offsets not being handled correctly on flipped items (did not affect any vanilla items). +- Adds a new status effect property called OffsetCopiesEntityTransform that can be used by status effects to configure the offset so it copies the current entity rotation/flipping/scaling. +- Fixed TargetSlot in RequiredItem not working properly on items that have multiple ItemContainers/inventories (only the first one was checked). +- Fixed melee weapons sometimes hitting characters whose limbs have been set to ignore collisions. More specifically, the weapon would still hit the character's "main collider". +- If a beacon station has a sonar transducer connected to the sonar monitor, and the monitor is set to use transducers, the transducer must be powered for the beacon mission to complete. +- Fix ContainedSpriteDepth being tied to the item's index in the container instead of the slot index. +- Fixed OnInserted StatusEffects triggering when you try to swap an item inside some other item but the swap fails. + +------------------------------------------------------------------------------------------------------------------------------------------------- v1.11.5.0 (Winter Update Hotfix 1) ------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Libraries/BarotraumaLibs/BarotraumaCore/BarotraumaCore.csproj b/Libraries/BarotraumaLibs/BarotraumaCore/BarotraumaCore.csproj index 43147b2b5..7cc2b89a1 100644 --- a/Libraries/BarotraumaLibs/BarotraumaCore/BarotraumaCore.csproj +++ b/Libraries/BarotraumaLibs/BarotraumaCore/BarotraumaCore.csproj @@ -1,28 +1,28 @@ - - - - net8.0 - Barotrauma - disable - enable - - - - full - ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 - true - x64 - - - - full - ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 - true - x64 - - - - - - - + + + + net8.0 + Barotrauma + disable + enable + + + + full + ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 + true + x64 + + + + full + ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 + true + x64 + + + + + + + diff --git a/Libraries/BarotraumaLibs/BarotraumaCore/Utils/ToolBoxCore.cs b/Libraries/BarotraumaLibs/BarotraumaCore/Utils/ToolBoxCore.cs index d4c7f54f2..e22177450 100644 --- a/Libraries/BarotraumaLibs/BarotraumaCore/Utils/ToolBoxCore.cs +++ b/Libraries/BarotraumaLibs/BarotraumaCore/Utils/ToolBoxCore.cs @@ -47,11 +47,17 @@ public static class ToolBoxCore byte[] inputBytes = Encoding.UTF8.GetBytes(str); byte[] hash = md5.ComputeHash(inputBytes); - UInt32 key = (UInt32)((str.Length & 0xff) << 24); //could use more of the hash here instead? - key |= (UInt32)(hash[hash.Length - 3] << 16); - key |= (UInt32)(hash[hash.Length - 2] << 8); - key |= (UInt32)(hash[hash.Length - 1]); - + //xor all of the bits of the hash together + UInt32 key = 0; + foreach (byte b in hash) + { + // Rotate the 32-bit value left by 5 bits: + // (key << 5) moves everything left, + // (key >> 27) brings the 5 bits that overflowed back around (32 - 5 = 27), + // OR'ing them together completes the rotate. + key = (key << 5) | (key >> 27); + key ^= b; + } return key; } diff --git a/Libraries/BarotraumaLibs/EosInterface/EosInterface.csproj b/Libraries/BarotraumaLibs/EosInterface/EosInterface.csproj index e366bb52f..1976acfca 100644 --- a/Libraries/BarotraumaLibs/EosInterface/EosInterface.csproj +++ b/Libraries/BarotraumaLibs/EosInterface/EosInterface.csproj @@ -1,26 +1,26 @@ - - - - net8.0 - disable - enable - Barotrauma - - - - ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 - true - x64 - - - - ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 - true - x64 - - - - - - - + + + + net8.0 + disable + enable + Barotrauma + + + + ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 + true + x64 + + + + ;NU1605;CS0114;CS0108;CS8597;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8606;CS8607;CS8608;CS8609;CS8610;CS8611;CS8612;CS8613;CS8614;CS8615;CS8616;CS8617;CS8618;CS8619;CS8620;CS8621;CS8622;CS8624;CS8625;CS8626;CS8629;CS8631;CS8632;CS8633;CS8634;CS8638;CS8643;CS8644;CS8645;CS8653;CS8654;CS8655;CS8667;CS8669;CS8670;CS8714;CS8717;CS8765 + true + x64 + + + + + + + diff --git a/Libraries/Concentus/.gitignore b/Libraries/Concentus/.gitignore index 629fe1100..fcd9a1be9 100644 --- a/Libraries/Concentus/.gitignore +++ b/Libraries/Concentus/.gitignore @@ -1,240 +1,240 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ -/Java/Concentus/target/ -/Java/ContentusTestConsole/ContentusTestConsole/target/ -/Java/ContentusTestConsole/ConcentusTestConsole/target/ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ +/Java/Concentus/target/ +/Java/ContentusTestConsole/ContentusTestConsole/target/ +/Java/ContentusTestConsole/ConcentusTestConsole/target/ /Java/ConcentusTestConsole/target/ \ No newline at end of file diff --git a/Libraries/Concentus/CSharp/Concentus/Concentus.NetStandard.csproj b/Libraries/Concentus/CSharp/Concentus/Concentus.NetStandard.csproj index 725dda808..99073a079 100644 --- a/Libraries/Concentus/CSharp/Concentus/Concentus.NetStandard.csproj +++ b/Libraries/Concentus/CSharp/Concentus/Concentus.NetStandard.csproj @@ -1,20 +1,20 @@ - - - - netstandard2.1 - AnyCPU;x64 - Concentus - Logan Stromberg - 1.1.6.0 - Copyright © Xiph.Org Foundation, Skype Limited, CSIRO, Microsoft Corp. - This package is a pure portable C# implementation of the Opus audio compression codec (see https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, repacketizer, as well as a port of the libspeexdsp resampler. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet streams - - https://github.com/lostromb/concentus - - - - full - true - - - + + + + netstandard2.1 + AnyCPU;x64 + Concentus + Logan Stromberg + 1.1.6.0 + Copyright © Xiph.Org Foundation, Skype Limited, CSIRO, Microsoft Corp. + This package is a pure portable C# implementation of the Opus audio compression codec (see https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, repacketizer, as well as a port of the libspeexdsp resampler. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet streams + + https://github.com/lostromb/concentus + + + + full + true + + + diff --git a/Libraries/Farseer Physics Engine 3.5/Farseer.NetStandard.csproj b/Libraries/Farseer Physics Engine 3.5/Farseer.NetStandard.csproj index 96e8ca92c..69fbafa2f 100644 --- a/Libraries/Farseer Physics Engine 3.5/Farseer.NetStandard.csproj +++ b/Libraries/Farseer Physics Engine 3.5/Farseer.NetStandard.csproj @@ -1,40 +1,40 @@ - - - - netstandard2.1 - FarseerPhysics - Copyright Ian Qvist © 2013 - Farseer Physics Engine - - 3.5.0.0 - Ian Qvist - AnyCPU;x64 - - - - TRACE - portable - true - - - - - - - - - - - - - - - - - - - - - - - + + + + netstandard2.1 + FarseerPhysics + Copyright Ian Qvist © 2013 + Farseer Physics Engine + + 3.5.0.0 + Ian Qvist + AnyCPU;x64 + + + + TRACE + portable + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Libraries/GameAnalytics/GA_SDK_NETSTANDARD/GA_SDK_NETSTANDARD.csproj b/Libraries/GameAnalytics/GA_SDK_NETSTANDARD/GA_SDK_NETSTANDARD.csproj index 6b99d030a..1a989ea0f 100644 --- a/Libraries/GameAnalytics/GA_SDK_NETSTANDARD/GA_SDK_NETSTANDARD.csproj +++ b/Libraries/GameAnalytics/GA_SDK_NETSTANDARD/GA_SDK_NETSTANDARD.csproj @@ -1,35 +1,35 @@ - - - - netstandard2.1 - GameAnalytics.NetStandard - GameAnalytics.Net - AnyCPU;x64 - Game Analytics - Copyright (c) 2016 Game Analytics - - - - TRACE;MONO - - - - TRACE;MONO - - - - TRACE;MONO - - - - TRACE;MONO - - - - - - - - - - + + + + netstandard2.1 + GameAnalytics.NetStandard + GameAnalytics.Net + AnyCPU;x64 + Game Analytics + Copyright (c) 2016 Game Analytics + + + + TRACE;MONO + + + + TRACE;MONO + + + + TRACE;MONO + + + + TRACE;MONO + + + + + + + + + + diff --git a/Libraries/SharpFont/Source/SharpFont/SharpFont.NetStandard.csproj b/Libraries/SharpFont/Source/SharpFont/SharpFont.NetStandard.csproj index a4477adaa..6f2368424 100644 --- a/Libraries/SharpFont/Source/SharpFont/SharpFont.NetStandard.csproj +++ b/Libraries/SharpFont/Source/SharpFont/SharpFont.NetStandard.csproj @@ -1,45 +1,45 @@ - - - - netstandard2.1 - SharpFont - SharpFont - Cross-platform FreeType bindings for C# - Robmaister - SharpFont - - Copyright (c) Robert Rouhani 2012-2016 - AnyCPU;x64 - - - - TRACE;DEBUG;SHARPFONT_PORTABLE - true - - - - TRACE;DEBUG;SHARPFONT_PORTABLE - true - 1701;1702;3021 - - - - TRACE;SHARPFONT_PORTABLE - true - - - - TRACE;SHARPFONT_PORTABLE - true - 1701;1702;3021 - - - - - - - - - - - + + + + netstandard2.1 + SharpFont + SharpFont + Cross-platform FreeType bindings for C# + Robmaister + SharpFont + + Copyright (c) Robert Rouhani 2012-2016 + AnyCPU;x64 + + + + TRACE;DEBUG;SHARPFONT_PORTABLE + true + + + + TRACE;DEBUG;SHARPFONT_PORTABLE + true + 1701;1702;3021 + + + + TRACE;SHARPFONT_PORTABLE + true + + + + TRACE;SHARPFONT_PORTABLE + true + 1701;1702;3021 + + + + + + + + + + + diff --git a/Libraries/XNATypes/XNATypes.csproj b/Libraries/XNATypes/XNATypes.csproj index 57fd8b083..b3b90d794 100644 --- a/Libraries/XNATypes/XNATypes.csproj +++ b/Libraries/XNATypes/XNATypes.csproj @@ -1,10 +1,10 @@ - - - - netstandard2.1 - AnyCPU;x64 - - - - - + + + + netstandard2.1 + AnyCPU;x64 + + + + + diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/common.props b/Libraries/webm_mem_playback/opus/win32/VS2015/common.props index 03cd45b0c..6c757d8b7 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/common.props +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/common.props @@ -1,82 +1,82 @@ - - - - - - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - Unicode - - - true - true - false - - - false - false - true - - - - Level3 - false - false - ..\..;..\..\include;..\..\silk;..\..\celt;..\..\win32;%(AdditionalIncludeDirectories) - HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - false - false - - - Console - - - true - Console - - - - - Guard - ProgramDatabase - NoExtensions - false - true - false - Disabled - false - false - Disabled - MultiThreadedDebug - MultiThreadedDebugDLL - true - false - - - true - - - - - false - None - true - true - false - Speed - Fast - Precise - true - true - true - MaxSpeed - MultiThreaded - MultiThreadedDLL - 16Bytes - - - false - - - + + + + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + Unicode + + + true + true + false + + + false + false + true + + + + Level3 + false + false + ..\..;..\..\include;..\..\silk;..\..\celt;..\..\win32;%(AdditionalIncludeDirectories) + HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + false + + + Console + + + true + Console + + + + + Guard + ProgramDatabase + NoExtensions + false + true + false + Disabled + false + false + Disabled + MultiThreadedDebug + MultiThreadedDebugDLL + true + false + + + true + + + + + false + None + true + true + false + Speed + Fast + Precise + true + true + true + MaxSpeed + MultiThreaded + MultiThreadedDLL + 16Bytes + + + false + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj b/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj index fc2241116..ae420d508 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj @@ -1,399 +1,399 @@ - - - - - DebugDLL_fixed - Win32 - - - DebugDLL_fixed - x64 - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL_fixed - Win32 - - - ReleaseDLL_fixed - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - Win32Proj - opus - {219EC965-228A-1824-174D-96449D05F88A} - - - - StaticLibrary - v142 - - - DynamicLibrary - v142 - - - DynamicLibrary - v142 - - - StaticLibrary - v142 - - - DynamicLibrary - v142 - - - DynamicLibrary - v142 - - - StaticLibrary - v142 - - - DynamicLibrary - v142 - - - DynamicLibrary - v142 - - - StaticLibrary - v142 - - - DynamicLibrary - v142 - - - DynamicLibrary - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\silk\fixed;..\..\silk\float;%(AdditionalIncludeDirectories) - DLL_EXPORT;%(PreprocessorDefinitions) - FIXED_POINT;%(PreprocessorDefinitions) - /arch:IA32 %(AdditionalOptions) - - - /ignore:4221 %(AdditionalOptions) - - - "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION - Generating version.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4244;%(DisableSpecificWarnings) - - - - - - - - - - - - - - - false - - - false - - - true - - - - - - - true - - - true - - - false - - - - - - - + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + Win32Proj + opus + {219EC965-228A-1824-174D-96449D05F88A} + + + + StaticLibrary + v142 + + + DynamicLibrary + v142 + + + DynamicLibrary + v142 + + + StaticLibrary + v142 + + + DynamicLibrary + v142 + + + DynamicLibrary + v142 + + + StaticLibrary + v142 + + + DynamicLibrary + v142 + + + DynamicLibrary + v142 + + + StaticLibrary + v142 + + + DynamicLibrary + v142 + + + DynamicLibrary + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\silk\fixed;..\..\silk\float;%(AdditionalIncludeDirectories) + DLL_EXPORT;%(PreprocessorDefinitions) + FIXED_POINT;%(PreprocessorDefinitions) + /arch:IA32 %(AdditionalOptions) + + + /ignore:4221 %(AdditionalOptions) + + + "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION + Generating version.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4244;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + false + + + false + + + true + + + + + + + true + + + true + + + false + + + + + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj.filters b/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj.filters index 47185c67d..97eb46551 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj.filters +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/opus.vcxproj.filters @@ -1,744 +1,744 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj b/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj index fcd971bb6..7ad4b5e21 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj @@ -1,171 +1,171 @@ - - - - - DebugDLL_fixed - Win32 - - - DebugDLL_fixed - x64 - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL_fixed - Win32 - - - ReleaseDLL_fixed - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - - {219ec965-228a-1824-174d-96449d05f88a} - - - - - - - {016C739D-6389-43BF-8D88-24B2BF6F620F} - Win32Proj - opus_demo - - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + + + + {016C739D-6389-43BF-8D88-24B2BF6F620F} + Win32Proj + opus_demo + + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj.filters b/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj.filters index dbcc8ae92..2eb113ac8 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj.filters +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/opus_demo.vcxproj.filters @@ -1,22 +1,22 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj index e428bd3f7..4ba7c8ae5 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj @@ -1,171 +1,171 @@ - - - - - DebugDLL_fixed - Win32 - - - DebugDLL_fixed - x64 - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL_fixed - Win32 - - - ReleaseDLL_fixed - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - {219ec965-228a-1824-174d-96449d05f88a} - - - - {1D257A17-D254-42E5-82D6-1C87A6EC775A} - Win32Proj - test_opus_api - - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {1D257A17-D254-42E5-82D6-1C87A6EC775A} + Win32Proj + test_opus_api + + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj.filters b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj.filters index 070c8ab01..383d19f71 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj.filters +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_api.vcxproj.filters @@ -1,14 +1,14 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj index cbf562183..8e4640094 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj @@ -1,171 +1,171 @@ - - - - - DebugDLL_fixed - Win32 - - - DebugDLL_fixed - x64 - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL_fixed - Win32 - - - ReleaseDLL_fixed - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - {219ec965-228a-1824-174d-96449d05f88a} - - - - {8578322A-1883-486B-B6FA-E0094B65C9F2} - Win32Proj - test_opus_api - - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {8578322A-1883-486B-B6FA-E0094B65C9F2} + Win32Proj + test_opus_api + + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj.filters b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj.filters index 588637e83..3036a4e70 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj.filters +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_decode.vcxproj.filters @@ -1,14 +1,14 @@ - - - - - {4a0dd677-931f-4728-afe5-b761149fc7eb} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - + + + + + {4a0dd677-931f-4728-afe5-b761149fc7eb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj index 5a313c31d..6804918a3 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj @@ -1,172 +1,172 @@ - - - - - DebugDLL_fixed - Win32 - - - DebugDLL_fixed - x64 - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL_fixed - Win32 - - - ReleaseDLL_fixed - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - - {219ec965-228a-1824-174d-96449d05f88a} - - - - {84DAA768-1A38-4312-BB61-4C78BB59E5B8} - Win32Proj - test_opus_api - - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - Application - v142 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {84DAA768-1A38-4312-BB61-4C78BB59E5B8} + Win32Proj + test_opus_api + + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj.filters b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj.filters index f04776380..4ed3bb9e7 100644 --- a/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj.filters +++ b/Libraries/webm_mem_playback/opus/win32/VS2015/test_opus_encode.vcxproj.filters @@ -1,17 +1,17 @@ - - - - - {546c8d9a-103e-4f78-972b-b44e8d3c8aba} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - Source Files - - + + + + + {546c8d9a-103e-4f78-972b-b44e8d3c8aba} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/Libraries/webm_mem_playback/opus/win32/genversion.bat b/Libraries/webm_mem_playback/opus/win32/genversion.bat index aea557393..1def7460b 100644 --- a/Libraries/webm_mem_playback/opus/win32/genversion.bat +++ b/Libraries/webm_mem_playback/opus/win32/genversion.bat @@ -1,37 +1,37 @@ -@echo off - -setlocal enableextensions enabledelayedexpansion - -for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v - -if not "%version%"=="" set version=!version:~1! && goto :gotversion - -if exist "%~dp0..\package_version" goto :getversion - -echo Git cannot be found, nor can package_version. Generating unknown version. - -set version=unknown - -goto :gotversion - -:getversion - -for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v -set version=!version:"=! - -:gotversion - -set version=!version: =! -set version_out=#define %~2 "%version%" - -echo %version_out%> "%~1_temp" - -echo n | comp "%~1_temp" "%~1" > NUL 2> NUL - -if not errorlevel 1 goto exit - -copy /y "%~1_temp" "%~1" - -:exit - -del "%~1_temp" +@echo off + +setlocal enableextensions enabledelayedexpansion + +for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v + +if not "%version%"=="" set version=!version:~1! && goto :gotversion + +if exist "%~dp0..\package_version" goto :getversion + +echo Git cannot be found, nor can package_version. Generating unknown version. + +set version=unknown + +goto :gotversion + +:getversion + +for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v +set version=!version:"=! + +:gotversion + +set version=!version: =! +set version_out=#define %~2 "%version%" + +echo %version_out%> "%~1_temp" + +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL + +if not errorlevel 1 goto exit + +copy /y "%~1_temp" "%~1" + +:exit + +del "%~1_temp" diff --git a/Libraries/webm_mem_playback/webm_mem_playback/webm-mem-playback.vcxproj b/Libraries/webm_mem_playback/webm_mem_playback/webm-mem-playback.vcxproj index 5a3253ee6..6e90faa56 100644 --- a/Libraries/webm_mem_playback/webm_mem_playback/webm-mem-playback.vcxproj +++ b/Libraries/webm_mem_playback/webm_mem_playback/webm-mem-playback.vcxproj @@ -1,148 +1,148 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {D0097438-DA4F-4E6D-87AC-7D99DDD276B2} - vpxmemplayback - 10.0 - webm_mem_playback - - - - DynamicLibrary - true - v142 - MultiByte - - - DynamicLibrary - false - v142 - true - MultiByte - - - DynamicLibrary - true - v142 - MultiByte - - - DynamicLibrary - false - v142 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - $(ProjectName)_$(Platform) - - - - Level3 - Disabled - true - true - ..\libwebm_x86_64_vs15;..\libvpx_x86_64_vs15;%(AdditionalIncludeDirectories) - - - %(AdditionalDependencies) - - - - - Level3 - Disabled - true - true - %(AdditionalIncludeDirectories) - MultiThreadedDebug - - - %(AdditionalDependencies) - - - - - Level3 - MaxSpeed - true - true - true - true - ..\libwebm_x86_64_vs15;..\libvpx_x86_64_vs15;%(AdditionalIncludeDirectories) - - - true - true - %(AdditionalDependencies) - - - - - Level3 - MaxSpeed - true - true - true - true - ..\libwebm_x86_vs19;..\libvpx_x64_vs15;..\opus\include;%(AdditionalIncludeDirectories) - MultiThreaded - Speed - - - true - true - ../libvpx_x64_vs15/$(Platform)/$(Configuration)/vpxmt.lib;../libwebm_x64_vs19/Release/libwebm.lib;../opus/win32/VS2015/x64/Release/opus.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {D0097438-DA4F-4E6D-87AC-7D99DDD276B2} + vpxmemplayback + 10.0 + webm_mem_playback + + + + DynamicLibrary + true + v142 + MultiByte + + + DynamicLibrary + false + v142 + true + MultiByte + + + DynamicLibrary + true + v142 + MultiByte + + + DynamicLibrary + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(ProjectName)_$(Platform) + + + + Level3 + Disabled + true + true + ..\libwebm_x86_64_vs15;..\libvpx_x86_64_vs15;%(AdditionalIncludeDirectories) + + + %(AdditionalDependencies) + + + + + Level3 + Disabled + true + true + %(AdditionalIncludeDirectories) + MultiThreadedDebug + + + %(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + ..\libwebm_x86_64_vs15;..\libvpx_x86_64_vs15;%(AdditionalIncludeDirectories) + + + true + true + %(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + ..\libwebm_x86_vs19;..\libvpx_x64_vs15;..\opus\include;%(AdditionalIncludeDirectories) + MultiThreaded + Speed + + + true + true + ../libvpx_x64_vs15/$(Platform)/$(Configuration)/vpxmt.lib;../libwebm_x64_vs19/Release/libwebm.lib;../opus/win32/VS2015/x64/Release/opus.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file