From ad190f18659b0a548bd3d3f61244e12ce31037c1 Mon Sep 17 00:00:00 2001 From: Rinary <72972221+Rinary1@users.noreply.github.com> Date: Wed, 13 Nov 2024 03:05:51 +0200 Subject: [PATCH] =?UTF-8?q?=D0=A5=D0=B8=D1=80=D1=83=D1=80=D0=B3=D0=B8?= =?UTF-8?q?=D1=8F=20(#607)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Surgery * translate strings * ru translate * second ru translate * fix * fix pizza icon * пу-пу-пу * fix damageeeee * fix * fix x2) --- .gitignore | 1 + Content.Client/_Sunrise/ChoiceControl.xaml | 17 + Content.Client/_Sunrise/ChoiceControl.xaml.cs | 27 + .../_Sunrise/Medical/Surgery/SurgeryBui.cs | 443 ++++++++ .../Medical/Surgery/SurgeryStepButton.xaml | 4 + .../Medical/Surgery/SurgeryStepButton.xaml.cs | 13 + .../_Sunrise/Medical/Surgery/SurgerySystem.cs | 17 + .../Medical/Surgery/SurgeryWindow.xaml | 30 + .../Medical/Surgery/SurgeryWindow.xaml.cs | 12 + .../Medical/Surgery/SurgerySystem.Steps.cs | 262 +++++ .../_Sunrise/Medical/Surgery/SurgerySystem.cs | 135 +++ Content.Shared/Body/Part/BodyPartComponent.cs | 5 +- .../Body/Systems/SharedBodySystem.Parts.cs | 41 + Content.Shared/Damage/DamageSpecifier.cs | 12 +- Content.Shared/DoAfter/DoAfterArgs.cs | 3 + Content.Shared/DoAfter/SharedDoAfterSystem.cs | 9 +- .../Eye/Blinding/Systems/BlindableSystem.cs | 15 +- .../Prototypes/TechDisciplinePrototype.cs | 2 +- .../_Sunrise/BaseLayerIdComponent.cs | 14 + .../Surgery/Components/SurgeryComponent.cs | 20 + .../Components/SurgeryProgressComponent.cs | 18 + .../Components/SurgeryStepComponent.cs | 29 + .../Components/SurgeryTargetComponent.cs | 8 + .../Medical/Surgery/Components/_Conditions.cs | 29 + .../Medical/Surgery/Components/_Organs.cs | 35 + .../Medical/Surgery/Components/_Parts.cs | 22 + .../Medical/Surgery/Components/_Steps.cs | 32 + .../Medical/Surgery/Components/_Tools.cs | 71 ++ .../Events/SurgeryCanPerformStepEvent.cs | 17 + .../Surgery/Events/SurgeryDoAfterEvent.cs | 19 + .../Surgery/Events/SurgeryStepEvent.cs | 15 + .../Surgery/Events/SurgeryValidEvent.cs | 10 + .../Medical/Surgery/ISurgeryToolComponent.cs | 7 + .../Surgery/SharedSurgerySystem.BaseSteps.cs | 290 +++++ .../Surgery/SharedSurgerySystem.Conditions.cs | 74 ++ .../Medical/Surgery/SharedSurgerySystem.cs | 142 +++ .../Medical/Surgery/StepInvalidReason.cs | 10 + .../_Sunrise/Medical/Surgery/SurgeryUI.cs | 25 + .../_Sunrise/Medical/Surgery/attributions.yml | 49 + .../_Sunrise/Medical/Surgery/cautery1.ogg | Bin 0 -> 34770 bytes .../_Sunrise/Medical/Surgery/cautery2.ogg | Bin 0 -> 16854 bytes .../_Sunrise/Medical/Surgery/hemostat1.ogg | Bin 0 -> 15729 bytes .../Audio/_Sunrise/Medical/Surgery/organ1.ogg | Bin 0 -> 18912 bytes .../Audio/_Sunrise/Medical/Surgery/organ2.ogg | Bin 0 -> 18946 bytes .../_Sunrise/Medical/Surgery/retractor1.ogg | Bin 0 -> 11537 bytes .../_Sunrise/Medical/Surgery/retractor2.ogg | Bin 0 -> 9915 bytes .../Audio/_Sunrise/Medical/Surgery/saw.ogg | Bin 0 -> 46750 bytes .../_Sunrise/Medical/Surgery/scalpel1.ogg | Bin 0 -> 13736 bytes .../_Sunrise/Medical/Surgery/scalpel2.ogg | Bin 0 -> 13098 bytes .../en-US/_strings/_sunrise/categories.ftl | 2 + .../_sunrise/lathe/lathe-categories.ftl | 2 + .../_sunrise/research/technologies.ftl | 6 + .../_sunrise/body/parts/cyberlimbs.ftl | 18 + .../catalog/fills/boxes/syndicate.ftl | 2 +- .../_sunrise/entities/clothing/belt/belts.ftl | 2 +- .../_sunrise/entities/clothing/eyes/hud.ftl | 1 - .../entities/clothing/hands/clocks.ftl | 2 +- .../_sunrise/entities/clothing/head/hats.ftl | 2 +- .../entities/clothing/neck/cloaks.ftl | 1 - .../entities/clothing/outerclothing/suits.ftl | 2 +- .../entities/clothing/shoes/magboots.ftl | 2 +- .../_sunrise/entities/effects/portal.ftl | 2 +- .../objects/clothing/biocode/hardsuits.ftl | 2 +- .../circuitboards/machine/production.ftl | 2 +- .../entities/objects/devices/exp_collars.ftl | 2 +- .../entities/objects/misc/bouquet.ftl | 2 +- .../_sunrise/entities/objects/misc/box.ftl | 2 +- .../entities/objects/tools/energydome.ftl | 2 +- .../structures/machines/pacificator.ftl | 2 +- .../structures/reflector/reflector.ftl | 2 + .../_sunrise/surgery/accents_steps.ftl | 6 + .../_sunrise/surgery/amputation_steps.ftl | 2 + .../_sunrise/surgery/attachment_steps.ftl | 12 + .../_sunrise/surgery/organs_steps.ftl | 136 +++ .../_sunrise/surgery/surgeries.ftl | 48 + .../_sunrise/surgery/surgery_steps.ftl | 24 + .../ru-RU/_prototypes/actions/vampire.ftl | 2 +- .../ru-RU/_prototypes/body/organs/base.ftl | 20 + .../electronics/exosuit_components.ftl | 2 +- .../objects/specific/medical/surgery.ftl | 10 + .../ru-RU/_prototypes/objectives/vampire.ftl | 2 +- .../ru-RU/_strings/Vampires/vampires.ftl | 36 +- .../ru-RU/_strings/_sunrise/categories.ftl | 2 + .../_strings/_sunrise/construction/steps.ftl | 2 +- .../_strings/_sunrise/expcollar/examine.ftl | 2 +- .../_strings/_sunrise/expcollar/listing.ftl | 2 +- .../_strings/_sunrise/expcollar/popups.ftl | 2 +- .../Locale/ru-RU/_strings/_sunrise/guns.ftl | 2 +- .../_sunrise/lathe/lathe-categories.ftl | 2 + .../ru-RU/_strings/_sunrise/lobby/lobby.ftl | 3 - .../ru-RU/_strings/_sunrise/mood/mood.ftl | 14 +- .../_sunrise/research/technologies.ftl | 4 + .../_strings/_sunrise/surgery/window.ftl | 9 + .../ru-RU/_strings/administration/antag.ftl | 2 +- .../components/hypospray-component.ftl | 2 +- .../components/injector-component.ftl | 2 +- .../game-presets/preset-vampire.ftl | 2 +- .../_strings/metabolism/metabolizer-types.ftl | 2 +- .../_strings/reagents/meta/physical-desc.ftl | 2 +- Resources/Prototypes/Body/Organs/arachnid.yml | 14 +- Resources/Prototypes/Body/Organs/base.yml | 141 +++ Resources/Prototypes/Body/Organs/diona.yml | 8 +- Resources/Prototypes/Body/Organs/human.yml | 20 +- .../Prototypes/Body/Organs/reptilian.yml | 2 +- Resources/Prototypes/Body/Organs/slime.yml | 2 +- Resources/Prototypes/Body/Parts/base.yml | 1 + .../Prototypes/Body/Prototypes/arachnid.yml | 1 + .../Prototypes/Body/Prototypes/diona.yml | 2 + .../Prototypes/Body/Prototypes/dwarf.yml | 1 + .../Body/Prototypes/gingerbread.yml | 1 + .../Prototypes/Body/Prototypes/human.yml | 1 + Resources/Prototypes/Body/Prototypes/moth.yml | 1 + .../Prototypes/Body/Prototypes/reptilian.yml | 1 + .../Prototypes/Body/Prototypes/slime.yml | 3 + Resources/Prototypes/Body/Prototypes/vox.yml | 1 + .../Catalog/Fills/Backpacks/duffelbag.yml | 10 +- .../Catalog/Fills/Crates/medical.yml | 3 +- .../Prototypes/Entities/Mobs/Species/base.yml | 3 + .../Objects/Specific/Medical/surgery.yml | 172 ++- .../Furniture/Tables/operating_table.yml | 1 + .../Entities/Structures/Machines/lathe.yml | 31 +- .../Entities/Structures/Machines/research.yml | 1 + .../Prototypes/EntityLists/Tools/surgery.yml | 10 +- .../Prototypes/Recipes/Lathes/medical.yml | 12 +- .../_Sunrise/Body/Parts/cyberlimbs.yml | 123 +++ .../_Sunrise/Recipes/Lathes/categories.yml | 8 + .../_Sunrise/Recipes/Lathes/medical.yml | 136 +++ .../_Sunrise/Research/disciplines.yml | 11 + .../Prototypes/_Sunrise/Research/medical.yml | 55 + .../_Sunrise/Species/cyberlimbs.yml | 47 + .../_Sunrise/Surgery/accents_steps.yml | 42 + .../_Sunrise/Surgery/amputation_steps.yml | 18 + .../_Sunrise/Surgery/attachment_steps.yml | 81 ++ .../_Sunrise/Surgery/organs_steps.yml | 987 ++++++++++++++++++ .../Prototypes/_Sunrise/Surgery/surgeries.yml | 526 ++++++++++ .../_Sunrise/Surgery/surgery_steps.yml | 174 +++ Resources/Prototypes/_Sunrise/categories.yml | 9 + .../Medical/Surgery/bone_gel.rsi/bone-gel.png | Bin 0 -> 529 bytes .../Surgery/bone_gel.rsi/inhand-left.png | Bin 0 -> 321 bytes .../Surgery/bone_gel.rsi/inhand-right.png | Bin 0 -> 321 bytes .../Medical/Surgery/bone_gel.rsi/meta.json | 22 + .../scissors.rsi/advanced-hemostat.png | Bin 0 -> 615 bytes .../scissors.rsi/advanced-retractor.png | Bin 0 -> 755 bytes .../Surgery/scissors.rsi/advanced-setter.png | Bin 0 -> 706 bytes .../Medical/Surgery/scissors.rsi/meta.json | 11 +- .../Species/Cyberlimbs/parts.rsi/icon.png | Bin 0 -> 788 bytes .../Species/Cyberlimbs/parts.rsi/l_arm.png | Bin 0 -> 683 bytes .../Species/Cyberlimbs/parts.rsi/l_foot.png | Bin 0 -> 273 bytes .../Species/Cyberlimbs/parts.rsi/l_hand.png | Bin 0 -> 348 bytes .../Species/Cyberlimbs/parts.rsi/l_leg.png | Bin 0 -> 577 bytes .../Species/Cyberlimbs/parts.rsi/meta.json | 160 +++ .../Species/Cyberlimbs/parts.rsi/r_arm.png | Bin 0 -> 696 bytes .../Species/Cyberlimbs/parts.rsi/r_foot.png | Bin 0 -> 272 bytes .../Species/Cyberlimbs/parts.rsi/r_hand.png | Bin 0 -> 361 bytes .../Species/Cyberlimbs/parts.rsi/r_leg.png | Bin 0 -> 570 bytes Tools/_sunrise/fluentformatter.py | 2 +- 156 files changed, 5118 insertions(+), 137 deletions(-) create mode 100644 Content.Client/_Sunrise/ChoiceControl.xaml create mode 100644 Content.Client/_Sunrise/ChoiceControl.xaml.cs create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgerySystem.cs create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgeryWindow.xaml create mode 100644 Content.Client/_Sunrise/Medical/Surgery/SurgeryWindow.xaml.cs create mode 100644 Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.Steps.cs create mode 100644 Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.cs create mode 100644 Content.Shared/_Sunrise/BaseLayerIdComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryProgressComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryStepComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryTargetComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/_Conditions.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/_Organs.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/_Parts.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/_Steps.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Components/_Tools.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryCanPerformStepEvent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryDoAfterEvent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryStepEvent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryValidEvent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/ISurgeryToolComponent.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.BaseSteps.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.Conditions.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/StepInvalidReason.cs create mode 100644 Content.Shared/_Sunrise/Medical/Surgery/SurgeryUI.cs create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/attributions.yml create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/cautery1.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/cautery2.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/hemostat1.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/organ1.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/organ2.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/retractor1.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/retractor2.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/saw.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/scalpel1.ogg create mode 100644 Resources/Audio/_Sunrise/Medical/Surgery/scalpel2.ogg create mode 100644 Resources/Locale/en-US/_strings/_sunrise/categories.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/body/parts/cyberlimbs.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/entities/structures/reflector/reflector.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/accents_steps.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/amputation_steps.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/attachment_steps.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/organs_steps.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/surgeries.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/_sunrise/surgery/surgery_steps.ftl create mode 100644 Resources/Locale/ru-RU/_prototypes/body/organs/base.ftl create mode 100644 Resources/Locale/ru-RU/_strings/_sunrise/categories.ftl create mode 100644 Resources/Locale/ru-RU/_strings/_sunrise/surgery/window.ftl create mode 100644 Resources/Prototypes/Body/Organs/base.yml create mode 100644 Resources/Prototypes/_Sunrise/Body/Parts/cyberlimbs.yml create mode 100644 Resources/Prototypes/_Sunrise/Research/disciplines.yml create mode 100644 Resources/Prototypes/_Sunrise/Research/medical.yml create mode 100644 Resources/Prototypes/_Sunrise/Species/cyberlimbs.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/accents_steps.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/amputation_steps.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/attachment_steps.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/organs_steps.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/surgeries.yml create mode 100644 Resources/Prototypes/_Sunrise/Surgery/surgery_steps.yml create mode 100644 Resources/Prototypes/_Sunrise/categories.yml create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/advanced-hemostat.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/advanced-retractor.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/advanced-setter.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/icon.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/l_arm.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/l_foot.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/l_hand.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/l_leg.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/meta.json create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/r_arm.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/r_foot.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/r_hand.png create mode 100644 Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/r_leg.png diff --git a/.gitignore b/.gitignore index 2dd5912047c..78866a96f64 100644 --- a/.gitignore +++ b/.gitignore @@ -306,3 +306,4 @@ Resources/MapImages # Direnv stuff .direnv/ +.idea/ \ No newline at end of file diff --git a/Content.Client/_Sunrise/ChoiceControl.xaml b/Content.Client/_Sunrise/ChoiceControl.xaml new file mode 100644 index 00000000000..a444070d107 --- /dev/null +++ b/Content.Client/_Sunrise/ChoiceControl.xaml @@ -0,0 +1,17 @@ + + + + + diff --git a/Content.Client/_Sunrise/ChoiceControl.xaml.cs b/Content.Client/_Sunrise/ChoiceControl.xaml.cs new file mode 100644 index 00000000000..841c9d6a2a0 --- /dev/null +++ b/Content.Client/_Sunrise/ChoiceControl.xaml.cs @@ -0,0 +1,27 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; +// Taken from RMC14 build. +// https://github.com/RMC-14/RMC-14 +namespace Content.Client._Sunrise; + +[GenerateTypedNameReferences] +[Virtual] +public partial class ChoiceControl : Control +{ + public ChoiceControl() => RobustXamlLoader.Load(this); + + public void Set(string name, Texture? texture) + { + NameLabel.SetMessage(name); + Texture.Texture = texture; + } + + public void Set(FormattedMessage msg, Texture? texture) + { + NameLabel.SetMessage(msg); + Texture.Texture = texture; + } +} diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs b/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs new file mode 100644 index 00000000000..df19251fbe1 --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs @@ -0,0 +1,443 @@ +using Content.Client.Administration.UI.CustomControls; +using Content.Client.Hands.Systems; +using Content.Shared._Sunrise.Medical.Surgery; +using Content.Shared.Body.Part; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using static Robust.Client.UserInterface.Control; + +namespace Content.Client._Sunrise.Medical.Surgery; +// Based on the RMC14 build. +// https://github.com/RMC-14/RMC-14 + +[UsedImplicitly] +public sealed class SurgeryBui : BoundUserInterface +{ + [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + private readonly SurgerySystem _system; + private readonly HandsSystem _hands; + + [ViewVariables] + private SurgeryWindow? _window; + + private EntityUid? _part; + private (EntityUid Ent, EntProtoId Proto)? _surgery; + private readonly List _previousSurgeries = new(); + + public SurgeryBui(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + _system = _entities.System(); + _hands = _entities.System(); + + _system.OnRefresh += UpdateDisabledPanel; + _hands.OnPlayerItemAdded += OnPlayerItemAdded; + } + private DateTime _lastRefresh = DateTime.UtcNow; + private (string k1, EntityUid k2) _throttling = ("", new EntityUid()); + private void OnPlayerItemAdded(string k1, EntityUid k2) + { + if (_throttling.k1.Equals(k1) && _throttling.k2.Equals(k2) && DateTime.UtcNow - _lastRefresh < TimeSpan.FromSeconds(1)) return; + _throttling = (k1, k2); + _lastRefresh = DateTime.UtcNow; + RefreshUI(); + } + protected override void Open() => UpdateState(State); + protected override void UpdateState(BoundUserInterfaceState? state) + { + if (state is SurgeryBuiState s) + Update(s); + } + + private void Update(SurgeryBuiState state) + { + TryInitWindow(); + + _window!.Surgeries.DisposeAllChildren(); + _window.Steps.DisposeAllChildren(); + _window.Parts.DisposeAllChildren(); + + View(ViewType.Parts); + + var oldSurgery = _surgery; + var oldPart = _part; + _part = null; + _surgery = null; + + var parts = new List>(state.Choices.Keys.Count); + foreach (var choice in state.Choices.Keys) + { + if (_entities.TryGetEntity(choice, out var ent) && + _entities.TryGetComponent(ent, out BodyPartComponent? part)) + { + parts.Add((ent.Value, part)); + } + } + + parts.Sort((a, b) => + { + static int GetScore(Entity part) + => part.Comp.PartType switch + { + BodyPartType.Head => 1, + BodyPartType.Torso => 2, + BodyPartType.Arm => 3, + BodyPartType.Hand => 4, + BodyPartType.Leg => 5, + BodyPartType.Foot => 6, + BodyPartType.Tail => 7, + BodyPartType.Other => 8, + _ => 0 + }; + + return GetScore(a) - GetScore(b); + }); + + foreach (var part in parts) + { + var netPart = _entities.GetNetEntity(part.Owner); + var surgeries = state.Choices[netPart]; + var partName = _entities.GetComponent(part).EntityName; + var partButton = new ChoiceControl(); + + partButton.Set(partName, null); + partButton.Button.OnPressed += _ => OnPartPressed(netPart, surgeries); + + _window.Parts.AddChild(partButton); + + foreach (var (surgeryId, suffix, isCompleted) in surgeries) + { + if (_system.GetSingleton(surgeryId) is not { } surgery || + !_entities.TryGetComponent(surgery, out SurgeryComponent? surgeryComp)) + { + continue; + } + + if (oldPart == part && oldSurgery?.Proto == surgeryId) + OnSurgeryPressed((surgery, surgeryComp), netPart, surgeryId); + } + + if (oldPart == part && oldSurgery == null) + OnPartPressed(netPart, surgeries); + } + + RefreshUI(); + + if (!_window.IsOpen) + _window.OpenCentered(); + } + + private void TryInitWindow() + { + if (_window != null) return; + _window = new SurgeryWindow(); + _window.OnClose += Close; + _window.Title = Loc.GetString("surgery-window-name"); + + _window.PartsButton.OnPressed += _ => + { + _part = null; + _surgery = null; + _previousSurgeries.Clear(); + View(ViewType.Parts); + }; + + _window.SurgeriesButton.OnPressed += _ => + { + _surgery = null; + _previousSurgeries.Clear(); + + if (!_entities.TryGetNetEntity(_part, out var netPart) || + State is not SurgeryBuiState s || + !s.Choices.TryGetValue(netPart.Value, out var surgeries)) + { + return; + } + + OnPartPressed(netPart.Value, surgeries); + }; + + _window.StepsButton.OnPressed += _ => + { + if (!_entities.TryGetNetEntity(_part, out var netPart) || + _previousSurgeries.Count == 0) + { + return; + } + + var last = _previousSurgeries[^1]; + _previousSurgeries.RemoveAt(_previousSurgeries.Count - 1); + + if (_system.GetSingleton(last) is not { } previousId || + !_entities.TryGetComponent(previousId, out SurgeryComponent? previous)) + { + return; + } + + OnSurgeryPressed((previousId, previous), netPart.Value, last); + }; + } + + private void AddStep(EntProtoId stepId, NetEntity netPart, EntProtoId surgeryId) + { + if (_window == null || + _system.GetSingleton(stepId) is not { } step) + { + return; + } + + var stepName = new FormattedMessage(); + stepName.AddText(_entities.GetComponent(step).EntityName); + + var stepButton = new SurgeryStepButton { Step = step }; + stepButton.Button.OnPressed += _ => SendMessage(new SurgeryStepChosenBuiMsg() + { + Step = stepId, + Part = netPart, + Surgery = surgeryId, + }); + + _window.Steps.AddChild(stepButton); + } + + private void OnSurgeryPressed(Entity surgery, NetEntity netPart, EntProtoId surgeryId) + { + if (_window == null) + return; + + _part = _entities.GetEntity(netPart); + _surgery = (surgery, surgeryId); + + _window.Steps.DisposeAllChildren(); + + if (surgery.Comp.Requirement is { } requirementId && _system.GetSingleton(requirementId) is { } requirement) + { + var label = new ChoiceControl(); + label.Button.OnPressed += _ => + { + _previousSurgeries.Add(surgeryId); + + if (_entities.TryGetComponent(requirement, out SurgeryComponent? requirementComp)) + OnSurgeryPressed((requirement, requirementComp), netPart, requirementId); + }; + + var msg = new FormattedMessage(); + var surgeryName = _entities.GetComponent(requirement).EntityName; + msg.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires", ("surgeryname", surgeryName))); + label.Set(msg, null); + + _window.Steps.AddChild(label); + _window.Steps.AddChild(new HSeparator(Color.FromHex("#4972A1")) { Margin = new Thickness(0, 0, 0, 1) }); + } + + foreach (var stepId in surgery.Comp.Steps) + { + AddStep(stepId, netPart, surgeryId); + } + + View(ViewType.Steps); + RefreshUI(); + } + + private void OnPartPressed(NetEntity netPart, List<(EntProtoId, string, bool)> surgeryIds) + { + if (_window == null) + return; + + _part = _entities.GetEntity(netPart); + + _window.Surgeries.DisposeAllChildren(); + + var surgeries = new List<(Entity Ent, EntProtoId Id, string Name, bool IsCompleted, Texture?)>(); + foreach (var (surgeryId, suffix, isCompleted) in surgeryIds) + { + if (_system.GetSingleton(surgeryId) is not { } surgery || + !_entities.TryGetComponent(surgery, out SurgeryComponent? surgeryComp)) + { + continue; + } + + var texture = _entities.GetComponentOrNull(surgery)?.Icon?.Default; + var name = $"{_entities.GetComponent(surgery).EntityName} {suffix}"; + surgeries.Add(((surgery, surgeryComp), surgeryId, name, isCompleted, texture)); + } + + surgeries.Sort((a, b) => + { + var priority = a.Ent.Comp.Priority.CompareTo(b.Ent.Comp.Priority); + if (priority != 0) + return priority; + + return string.Compare(a.Name, b.Name, StringComparison.Ordinal); + }); + + foreach (var (Ent, Id, Name, IsCompleted, texture) in surgeries) + { + var surgeryButton = new ChoiceControl(); + + surgeryButton.Set(Name, texture); + if(IsCompleted) + surgeryButton.Button.Modulate = Color.Green; + surgeryButton.Button.OnPressed += _ => OnSurgeryPressed(Ent, netPart, Id); + _window.Surgeries.AddChild(surgeryButton); + } + + RefreshUI(); + View(ViewType.Surgeries); + } + + private void RefreshUI() + { + if (_window == null || + !_entities.HasComponent(_surgery?.Ent) || + !_entities.TryGetComponent(_part, out BodyPartComponent? part)) + { + return; + } + + var next = _system.GetNextStep(Owner, _part.Value, _surgery.Value.Ent); + var i = 0; + foreach (var child in _window.Steps.Children) + { + if (child is not SurgeryStepButton stepButton) + continue; + + var status = StepStatus.Incomplete; + if (next == null) + { + status = StepStatus.Complete; + } + else if (next.Value.Surgery.Owner != _surgery.Value.Ent) + { + status = StepStatus.Incomplete; + } + else if (next.Value.Step == i) + { + status = StepStatus.Next; + } + else if (i < next.Value.Step) + { + status = StepStatus.Complete; + } + + stepButton.Button.Disabled = status != StepStatus.Next; + + var stepName = new FormattedMessage(); + stepName.AddText(_entities.GetComponent(stepButton.Step).EntityName); + + if (status == StepStatus.Complete) + { + stepButton.Button.Modulate = Color.Green; + } + else if (status == StepStatus.Next) + { + stepButton.Button.Modulate = Color.White; + if (_player.LocalEntity is { } player && + !_system.CanPerformStep(player, Owner, part.PartType, stepButton.Step, false, out var popup, out var reason, out _)) + { + stepButton.ToolTip = popup; + stepButton.Button.Disabled = true; + + switch (reason) + { + case StepInvalidReason.NeedsOperatingTable: + stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-table")); + break; + case StepInvalidReason.Armor: + stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-undress")); + break; + case StepInvalidReason.MissingTool: + stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-tool")); + break; + } + } + } + + var texture = _entities.GetComponentOrNull(stepButton.Step)?.Icon?.Default; + stepButton.Set(stepName, texture); + i++; + } + } + + private void UpdateDisabledPanel() + { + if (_window == null) + return; + + if (_system.IsLyingDown(Owner)) + { + _window.DisabledPanel.Visible = false; + _window.DisabledPanel.MouseFilter = MouseFilterMode.Ignore; + return; + } + + _window.DisabledPanel.Visible = true; + if (_window.DisabledLabel.GetMessage() is null) + { + var text = new FormattedMessage(); + text.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-laydown")); + _window.DisabledLabel.SetMessage(text); + } + + _window.DisabledPanel.MouseFilter = MouseFilterMode.Stop; + } + + private void View(ViewType type) + { + if (_window == null) + return; + + _window.PartsButton.Parent!.Margin = new Thickness(0, 0, 0, 10); + + _window.Parts.Visible = type == ViewType.Parts; + _window.PartsButton.Disabled = type == ViewType.Parts; + + _window.Surgeries.Visible = type == ViewType.Surgeries; + _window.SurgeriesButton.Disabled = type != ViewType.Steps; + + _window.Steps.Visible = type == ViewType.Steps; + _window.StepsButton.Disabled = type != ViewType.Steps || _previousSurgeries.Count == 0; + + if (_entities.TryGetComponent(_part, out MetaDataComponent? partMeta) && + _entities.TryGetComponent(_surgery?.Ent, out MetaDataComponent? surgeryMeta)) + { + _window.Title = $"{Loc.GetString("surgery-window-name")} - {partMeta.EntityName}, {surgeryMeta.EntityName}"; + } + else if (partMeta != null) + { + _window.Title = $"{Loc.GetString("surgery-window-name")} - {partMeta.EntityName}"; + } + else + { + _window.Title = Loc.GetString("surgery-window-name"); + } + } + + private enum ViewType + { + Parts, + Surgeries, + Steps + } + + private enum StepStatus + { + Next, + Complete, + Incomplete + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + _window?.Dispose(); + _system.OnRefresh -= UpdateDisabledPanel; + _hands.OnPlayerItemAdded -= OnPlayerItemAdded; + } +} diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml new file mode 100644 index 00000000000..6b08f040e6e --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml @@ -0,0 +1,4 @@ + + diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs new file mode 100644 index 00000000000..90f3e3fdf45 --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs @@ -0,0 +1,13 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._Sunrise.Medical.Surgery; +// Based on the RMC14. +// https://github.com/RMC-14/RMC-14 +[GenerateTypedNameReferences] +public sealed partial class SurgeryStepButton : ChoiceControl +{ + public EntityUid Step { get; set; } + + public SurgeryStepButton() => RobustXamlLoader.Load(this); +} diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgerySystem.cs b/Content.Client/_Sunrise/Medical/Surgery/SurgerySystem.cs new file mode 100644 index 00000000000..7668fed97c3 --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgerySystem.cs @@ -0,0 +1,17 @@ +using Content.Shared._Sunrise.Medical.Surgery; + +namespace Content.Client._Sunrise.Medical.Surgery; +// Based on the RMC14. +// https://github.com/RMC-14/RMC-14 +public sealed class SurgerySystem : SharedSurgerySystem +{ + public event Action? OnRefresh; + public override void Update(float frameTime) + { + _delayAccumulator += frameTime; + if (_delayAccumulator > 1) { + _delayAccumulator = 0; + OnRefresh?.Invoke(); + } + } +} diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryWindow.xaml b/Content.Client/_Sunrise/Medical/Surgery/SurgeryWindow.xaml new file mode 100644 index 00000000000..42b770950ac --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryWindow.xaml @@ -0,0 +1,30 @@ + + + +