diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 5c1f94f3332..fe679554ae6 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -122,6 +122,19 @@ public override void Init() _prototypeManager.RegisterIgnore("nukeopsRole"); _prototypeManager.RegisterIgnore("ghostRoleRaffleDecider"); + //DarkStation + _prototypeManager.RegisterIgnore("symptom"); + _prototypeManager.RegisterIgnore("stationGoal"); + _prototypeManager.RegisterIgnore("narsiAbilityPrototype"); + _prototypeManager.RegisterIgnore("narsiRitualCategory"); + _prototypeManager.RegisterIgnore("narsiRitual"); + _prototypeManager.RegisterIgnore("diseaseBlacklistPrototype"); + _prototypeManager.RegisterIgnore("disease"); + _prototypeManager.RegisterIgnore("diseaseCure"); + _prototypeManager.RegisterIgnore("diseaseStage"); + _prototypeManager.RegisterIgnore("SCPStationGoal"); + _prototypeManager.RegisterIgnore("salaries"); + _componentFactory.GenerateNetIds(); _adminManager.Initialize(); _screenshotHook.Initialize(); diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml index aae8785b1fe..8804b5ee33c 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml @@ -1,64 +1,65 @@ - - - - - + + + + diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs index fd3615d59f5..ae354b209d1 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs @@ -1,20 +1,13 @@ using System.Linq; using System.Numerics; -using Content.Client.Message; +using System.Text; using Content.Shared.Atmos; using Content.Client.UserInterface.Controls; -using Content.Shared.Alert; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; -using Content.Shared.Humanoid; -using Content.Shared.Humanoid.Prototypes; using Content.Shared.IdentityManagement; -using Content.Shared.Inventory; using Content.Shared.MedicalScanner; -using Content.Shared.Mobs; -using Content.Shared.Mobs.Components; -using Content.Shared.Mobs.Systems; using Content.Shared.Nutrition.Components; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; @@ -36,6 +29,9 @@ public sealed partial class HealthAnalyzerWindow : FancyWindow private readonly IPrototypeManager _prototypes; private readonly IResourceCache _cache; + private const int AnalyzerHeight = 430; + private const int AnalyzerWidth = 600; + public HealthAnalyzerWindow() { RobustXamlLoader.Load(this); @@ -45,10 +41,20 @@ public HealthAnalyzerWindow() _spriteSystem = _entityManager.System(); _prototypes = dependencies.Resolve(); _cache = dependencies.Resolve(); + SetupSplitContainer(); + } + private void SetupSplitContainer() + { + SplitContainer.ResizeMode = SplitContainer.SplitResizeMode.RespectChildrenMinSize; + SplitContainer.SplitWidth = 2; + SplitContainer.SplitEdgeSeparation = 1f; + SplitContainer.StretchDirection = SplitContainer.SplitStretchDirection.TopLeft; } public void Populate(HealthAnalyzerScannedUserMessage msg) { + GroupsContainer.RemoveAllChildren(); + var target = _entityManager.GetEntity(msg.TargetEntity); if (target == null @@ -60,109 +66,92 @@ public void Populate(HealthAnalyzerScannedUserMessage msg) NoPatientDataText.Visible = false; - // Scan Mode - - ScanModeLabel.Text = msg.ScanMode.HasValue - ? msg.ScanMode.Value - ? Loc.GetString("health-analyzer-window-scan-mode-active") - : Loc.GetString("health-analyzer-window-scan-mode-inactive") - : Loc.GetString("health-analyzer-window-entity-unknown-text"); - - ScanModeLabel.FontColorOverride = msg.ScanMode.HasValue && msg.ScanMode.Value ? Color.Green : Color.Red; - - // Patient Information - - SpriteView.SetEntity(target.Value); - SpriteView.Visible = msg.ScanMode.HasValue && msg.ScanMode.Value; - NoDataTex.Visible = !SpriteView.Visible; - - var name = new FormattedMessage(); - name.PushColor(Color.White); - name.AddText(_entityManager.HasComponent(target.Value) - ? Identity.Name(target.Value, _entityManager) - : Loc.GetString("health-analyzer-window-entity-unknown-text")); - NameLabel.SetMessage(name); - - SpeciesLabel.Text = - _entityManager.TryGetComponent(target.Value, - out var humanoidAppearanceComponent) - ? Loc.GetString(_prototypes.Index(humanoidAppearanceComponent.Species).Name) - : Loc.GetString("health-analyzer-window-entity-unknown-species-text"); - - // Basic Diagnostic - - TemperatureLabel.Text = !float.IsNaN(msg.Temperature) - ? $"{msg.Temperature - Atmospherics.T0C:F1} °C ({msg.Temperature:F1} K)" - : Loc.GetString("health-analyzer-window-entity-unknown-value-text"); - - BloodLabel.Text = !float.IsNaN(msg.BloodLevel) - ? $"{msg.BloodLevel * 100:F1} %" - : Loc.GetString("health-analyzer-window-entity-unknown-value-text"); - - StatusLabel.Text = - _entityManager.TryGetComponent(target.Value, out var mobStateComponent) - ? GetStatus(mobStateComponent.CurrentState) - : Loc.GetString("health-analyzer-window-entity-unknown-text"); - - // Total Damage - - DamageLabel.Text = damageable.TotalDamage.ToString(); - - // Alerts + string entityName = Loc.GetString("health-analyzer-window-entity-unknown-text"); + if (_entityManager.HasComponent(target.Value)) + { + entityName = Identity.Name(target.Value, _entityManager); + } - var showAlerts = msg.Unrevivable == true || msg.Bleeding == true; + if (msg.ScanMode.HasValue) + { + ScanModePanel.Visible = true; + ScanModeText.Text = Loc.GetString(msg.ScanMode.Value ? "health-analyzer-window-scan-mode-active" : "health-analyzer-window-scan-mode-inactive"); + ScanModeText.FontColorOverride = msg.ScanMode.Value ? Color.Green : Color.Red; + } + else + { + ScanModePanel.Visible = false; + } - AlertsDivider.Visible = showAlerts; - AlertsContainer.Visible = showAlerts; + PatientName.Text = Loc.GetString( + "health-analyzer-window-entity-health-text", + ("entityName", entityName) + ); - if (showAlerts) - AlertsContainer.DisposeAllChildren(); + Temperature.Text = Loc.GetString("health-analyzer-window-entity-temperature-text", + ("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - Atmospherics.T0C:F1} °C ({msg.Temperature:F1} K)") + ); - if (msg.Unrevivable == true) - AlertsContainer.AddChild(new RichTextLabel - { - Text = Loc.GetString("health-analyzer-window-entity-unrevivable-text"), - Margin = new Thickness(0, 4), - MaxWidth = 300 - }); + BloodLevel.Text = Loc.GetString("health-analyzer-window-entity-blood-level-text", + ("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %") + ); if (msg.Bleeding == true) - AlertsContainer.AddChild(new RichTextLabel - { - Text = Loc.GetString("health-analyzer-window-entity-bleeding-text"), - Margin = new Thickness(0, 4), - MaxWidth = 300 - }); + { + Bleeding.Text = Loc.GetString("health-analyzer-window-entity-bleeding-text"); + Bleeding.FontColorOverride = Color.Red; + } + else + { + Bleeding.Text = string.Empty; // Clear the text + } - // Damage Groups + patientDamageAmount.Text = Loc.GetString( + "health-analyzer-window-entity-damage-total-text", + ("amount", damageable.TotalDamage) + ); var damageSortedGroups = - damageable.DamagePerGroup.OrderByDescending(damage => damage.Value) + damageable.DamagePerGroup.OrderBy(damage => damage.Value) .ToDictionary(x => x.Key, x => x.Value); - IReadOnlyDictionary damagePerType = damageable.Damage.DamageDict; DrawDiagnosticGroups(damageSortedGroups, damagePerType); + DrawOrgansState(msg.OrganConditions); + + if (_entityManager.TryGetComponent(target, out HungerComponent? hunger) + && hunger.StarvationDamage != null + && hunger.CurrentThreshold <= HungerThreshold.Starving) + { + var box = new Control { Margin = new Thickness(0, 0, 0, 15) }; + + box.AddChild(CreateDiagnosticGroupTitle( + Loc.GetString("health-analyzer-window-malnutrition"), + "malnutrition")); + + GroupsContainer.AddChild(box); + } + + SetHeight = AnalyzerHeight; + SetWidth = AnalyzerWidth; } - private static string GetStatus(MobState mobState) + private void DrawOrgansState(Dictionary organs) { - return mobState switch + var organsState = new StringBuilder("Состояние органов: \n"); + foreach (var organ in organs) { - MobState.Alive => Loc.GetString("health-analyzer-window-entity-alive-text"), - MobState.Critical => Loc.GetString("health-analyzer-window-entity-critical-text"), - MobState.Dead => Loc.GetString("health-analyzer-window-entity-dead-text"), - _ => Loc.GetString("health-analyzer-window-entity-unknown-text"), - }; + organsState.Append($"\n{organ.Key}: {organ.Value}\n"); + } + OrganStatus.SetMessage(FormattedMessage.FromMarkup(organsState.ToString())); } - private void DrawDiagnosticGroups( - Dictionary groups, - IReadOnlyDictionary damageDict) + Dictionary groups, IReadOnlyDictionary damageDict) { - GroupsContainer.RemoveAllChildren(); + HashSet shownTypes = new(); - foreach (var (damageGroupId, damageAmount) in groups) + // Show the total damage and type breakdown for each damage group. + foreach (var (damageGroupId, damageAmount) in groups.Reverse()) { if (damageAmount == 0) continue; @@ -175,6 +164,7 @@ private void DrawDiagnosticGroups( var groupContainer = new BoxContainer { + Margin = new Thickness(0, 0, 0, 15), Align = BoxContainer.AlignMode.Begin, Orientation = BoxContainer.LayoutOrientation.Vertical, }; @@ -188,16 +178,23 @@ private void DrawDiagnosticGroups( foreach (var type in group.DamageTypes) { - if (!damageDict.TryGetValue(type, out var typeAmount) || typeAmount <= 0) - continue; - - var damageString = Loc.GetString( - "health-analyzer-window-damage-type-text", - ("damageType", _prototypes.Index(type).LocalizedName), - ("amount", typeAmount) - ); - - groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, " · "))); + if (damageDict.TryGetValue(type, out var typeAmount) && typeAmount > 0) + { + // If damage types are allowed to belong to more than one damage group, + // they may appear twice here. Mark them as duplicate. + if (shownTypes.Contains(type)) + continue; + + shownTypes.Add(type); + + var damageString = Loc.GetString( + "health-analyzer-window-damage-type-text", + ("damageType", _prototypes.Index(type).LocalizedName), + ("amount", typeAmount) + ); + + groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, "- "))); + } } } } @@ -220,6 +217,7 @@ private static Label CreateDiagnosticItemLabel(string text) { return new Label { + Margin = new Thickness(2, 2), Text = text, }; } @@ -228,13 +226,13 @@ private BoxContainer CreateDiagnosticGroupTitle(string text, string id) { var rootContainer = new BoxContainer { - Margin = new Thickness(0, 6, 0, 0), VerticalAlignment = VAlignment.Bottom, - Orientation = BoxContainer.LayoutOrientation.Horizontal, + Orientation = BoxContainer.LayoutOrientation.Horizontal }; rootContainer.AddChild(new TextureRect { + Margin = new Thickness(0, 3), SetSize = new Vector2(30, 30), Texture = GetTexture(id.ToLower()) }); diff --git a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs index 6eb5dd9ec98..068806823eb 100644 --- a/Content.Client/Humanoid/HumanoidAppearanceSystem.cs +++ b/Content.Client/Humanoid/HumanoidAppearanceSystem.cs @@ -48,14 +48,14 @@ private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent { oldLayers.Remove(key); if (!component.CustomBaseLayers.ContainsKey(key)) - SetLayerData(component, sprite, key, id, sexMorph: true); + SetLayerData(component, sprite, key, id, false, sexMorph: true); } // add custom layers foreach (var (key, info) in component.CustomBaseLayers) { oldLayers.Remove(key); - SetLayerData(component, sprite, key, info.Id, sexMorph: false, color: info.Color); + SetLayerData(component, sprite, key, info.Id, false, sexMorph: false, color: info.Color); } // hide old layers @@ -72,6 +72,7 @@ private void SetLayerData( SpriteComponent sprite, HumanoidVisualLayers key, string? protoId, + bool ignoreSkinByCustom, bool sexMorph = false, Color? color = null) { @@ -91,7 +92,7 @@ private void SetLayerData( var proto = _prototypeManager.Index(protoId); component.BaseLayers[key] = proto; - if (proto.MatchSkin) + if (proto.MatchSkin && !ignoreSkinByCustom) layer.Color = component.SkinColor.WithAlpha(proto.LayerAlpha); if (proto.BaseSprite != null) diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs index 4cde587c58c..86ae3f9f362 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierWindow.xaml.cs @@ -57,7 +57,7 @@ private void OnStateChanged(HumanoidVisualLayers layer, HumanoidBaseLayerModifie } string? state = _protoMan.HasIndex(modifier.Text) ? modifier.Text : null; - OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, modifier.Color)); + OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, false, modifier.Color)); } public void SetState( MarkingSet markings, diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs index 370188e3c61..1d3e96651d7 100644 --- a/Content.Client/IoC/ClientContentIoC.cs +++ b/Content.Client/IoC/ClientContentIoC.cs @@ -1,3 +1,4 @@ +using Content.Client._c4llv07e.Bridges; using Content.Client.Administration.Managers; using Content.Client.Changelog; using Content.Client.Chat.Managers; @@ -59,6 +60,8 @@ public static void Register() collection.Register(); collection.Register(); collection.Register(); + // Adventure Space + collection.RegisterInstance(new StubTargetDollWidgetBridge()); } } } diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraNavMapControl.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraNavMapControl.cs new file mode 100644 index 00000000000..bd4f6a7c349 --- /dev/null +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraNavMapControl.cs @@ -0,0 +1,13 @@ +using Content.Client.Pinpointer.UI; + +namespace Content.Client.SurveillanceCamera.UI; + +public sealed partial class SurveillanceCameraNavMapControl : NavMapControl +{ + public SurveillanceCameraNavMapControl() : base() + { + WallColor = new Color(100, 100, 100); + TileColor = new(71, 42, 72, 0); + BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity)); + } +} diff --git a/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml b/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml index 54aeffe72c9..a0ebdbe7b79 100644 --- a/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml +++ b/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml @@ -1,4 +1,4 @@ - + diff --git a/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml.cs b/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml.cs index 12f8422aeb2..b45ac6491ad 100644 --- a/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml.cs +++ b/Content.Client/UserInterface/Screens/DefaultGameScreen.xaml.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System.Numerics; +using Content.Client._Adventure.Medical.Surgery.UI; using Content.Client.UserInterface.Systems.Chat.Widgets; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; @@ -22,6 +23,7 @@ public DefaultGameScreen() SetAnchorAndMarginPreset(Hotbar, LayoutPreset.BottomWide, margin: 5); SetAnchorAndMarginPreset(Chat, LayoutPreset.TopRight, margin: 10); SetAnchorAndMarginPreset(Alerts, LayoutPreset.TopRight, margin: 10); + SetAnchorAndMarginPreset(TargetDoll, LayoutPreset.BottomRight, margin: 70); Chat.OnResized += ChatOnResized; Chat.OnChatResizeFinish += ChatOnResizeFinish; diff --git a/Content.Client/VendingMachines/UI/EconomyVendingMachineMenu.xaml b/Content.Client/VendingMachines/UI/EconomyVendingMachineMenu.xaml new file mode 100644 index 00000000000..da1acb48f63 --- /dev/null +++ b/Content.Client/VendingMachines/UI/EconomyVendingMachineMenu.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + +