diff --git a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs index 6fc07785b2..fcb6fa5114 100644 --- a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs +++ b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Clothing; using Content.Shared.Clothing.Components; using Content.Shared.Hands; +using Content.Shared.Hands.Components; using Content.Shared.Item; using Content.Shared.Rounding; using Robust.Client.GameObjects; @@ -166,7 +167,17 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem "left", + HandLocation.Right => "right", + _ => "left" // bruh? Maybe add a middle hand for something, so this has some logic + }; + + var key = $"{heldPrefix}{locationString}{component.InHandsFillBaseName}{closestFillSprite}"; + // Sunrise-end layer.State = key; diff --git a/Content.Client/_Sunrise/Medical/Surgery/CustomLimbVisualizerSystem.cs b/Content.Client/_Sunrise/Medical/Surgery/CustomLimbVisualizerSystem.cs new file mode 100644 index 0000000000..ba22c74405 --- /dev/null +++ b/Content.Client/_Sunrise/Medical/Surgery/CustomLimbVisualizerSystem.cs @@ -0,0 +1,125 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Interaction; +using Content.Shared.Item; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Toggleable; +using Content.Shared.Verbs; +using Robust.Client.GameObjects; +using Content.Shared._Sunrise.Medical.Surgery; +using Content.Shared.Humanoid; +using System; +using System.Numerics; +using Robust.Client.Graphics; +using Content.Shared.DisplacementMap; +using Content.Client.DisplacementMap; +using System.Reflection; +using Robust.Shared.Graphics.RSI; +using Robust.Shared.Utility; +using Content.Client.Clothing; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using System.Linq; + +namespace Content.Client._Sunrise.Medical.Surgery; + +public sealed class CustomLimbVisualizerSystem : EntitySystem +{ + [Dependency] private readonly DisplacementMapSystem _displacement = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnChanged); + } + + private void OnChanged(Entity ent, ref AfterAutoHandleStateEvent _) => OnChanged(ent); + private void OnChanged(Entity ent, bool repeat = true) + { + if (!TryComp(ent.Owner, out var sprite)) + return; + + var old = ent.Comp.CachedLayers.ToHashSet(); + ent.Comp.CachedLayers.Clear(); + + foreach (var item in ent.Comp.Layers) + { + if (!item.Value.HasValue || !TryComp(GetEntity(item.Value), out var layerSprite)) + { + if (repeat) Timer.Spawn(TimeSpan.FromMilliseconds(150), () => OnChanged(ent, false)); + return; + } + string? state = null; + if (TryComp(GetEntity(item.Value), out var itemComp) && itemComp.HeldPrefix is not null) + state = $"{itemComp.HeldPrefix}-"; + + var offset = Vector2.Zero; + switch (item.Key) + { + case HumanoidVisualLayers.LArm: + case HumanoidVisualLayers.LHand: + case HumanoidVisualLayers.LLeg: + case HumanoidVisualLayers.LFoot: + state += "inhand-left"; + break; + case HumanoidVisualLayers.RArm: + case HumanoidVisualLayers.RHand: + case HumanoidVisualLayers.RLeg: + case HumanoidVisualLayers.RFoot: + state += "inhand-right"; + break; + } + if (state is null) continue; + + switch (item.Key) + { + case HumanoidVisualLayers.LArm: + offset = new Vector2(0, 0.1875f); + break; + case HumanoidVisualLayers.LHand: + offset = new Vector2(0, 0.09375f); + break; + case HumanoidVisualLayers.LLeg: + offset = new Vector2(0, -0.15625f); + break; + case HumanoidVisualLayers.LFoot: + offset = new Vector2(0, -0.34375f); + break; + case HumanoidVisualLayers.RArm: + offset = new Vector2(0, 0.1875f); + break; + case HumanoidVisualLayers.RHand: + offset = new Vector2(0, 0.09375f); + break; + case HumanoidVisualLayers.RLeg: + offset = new Vector2(0, -0.15625f); + break; + case HumanoidVisualLayers.RFoot: + offset = new Vector2(0, -0.34375f); + break; + } + if (layerSprite?.BaseRSI?.TryGetState(state, out var rsiState) ?? false) + { + var index = sprite.LayerMapReserveBlank($"custom-{item.Key}"); + + sprite.LayerSetState(index, rsiState.StateId, layerSprite.BaseRSI); + sprite.LayerSetOffset(index, offset); + sprite.LayerSetVisible(index, true); + ent.Comp.CachedLayers.Add(item.Key); + } + + //if (ent.Comp.Displacements.TryGetValue(item.Key, out var displacementData) && !ent.Comp.CachedLayers.Contains($"{item.Key}-displacement")) + //{ + // sprite.LayerMapSet(item.Key.ToString(), (int)item.Key); + // _displacement.TryAddDisplacement(displacementData, sprite, (int)item.Key, item.Key.ToString(), ent.Comp.CachedLayers); + //} + } + + foreach (var layer in old) + if (!ent.Comp.CachedLayers.Contains(layer)) + { + var index = sprite.LayerMapReserveBlank($"custom-{layer}"); + sprite.LayerSetVisible(layer, false); + } + } +} diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs b/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs index 8bf5adceec..40b8e90d24 100644 --- a/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryBui.cs @@ -1,14 +1,17 @@ -using Content.Client._Sunrise.Choice; -using Content.Client.Administration.UI.CustomControls; +using Content.Client.Administration.UI.CustomControls; using Content.Client.Hands.Systems; +using Content.Client._Sunrise.Choice; 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; +using Content.Shared.Timing; +using Robust.Shared.Timing; namespace Content.Client._Sunrise.Medical.Surgery; // Based on the RMC14 build. @@ -19,7 +22,7 @@ public sealed class SurgeryBui : BoundUserInterface { [Dependency] private readonly IEntityManager _entities = default!; [Dependency] private readonly IPlayerManager _player = default!; - + [Dependency] private readonly IGameTiming _game = default!; private readonly SurgerySystem _system; private readonly HandsSystem _hands; @@ -38,16 +41,17 @@ public sealed class SurgeryBui : BoundUserInterface _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; + if (!_game.IsFirstTimePredicted) return; RefreshUI(); } - protected override void Open() => UpdateState(State); + protected override void Open() + { + base.Open(); + UpdateState(State); + } + protected override void UpdateState(BoundUserInterfaceState? state) { if (state is SurgeryBuiState s) @@ -215,24 +219,30 @@ public sealed class SurgeryBui : BoundUserInterface _window.Steps.DisposeAllChildren(); - if (surgery.Comp.Requirement is { } requirementId && _system.GetSingleton(requirementId) is { } requirement) + if (surgery.Comp.Requirement is { } requirementIds) { - var label = new ChoiceControl(); - label.Button.OnPressed += _ => + foreach (var requirementId in requirementIds) { - _previousSurgeries.Add(surgeryId); + if (_system.GetSingleton(requirementId) is { } requirement && _entities.TryGetComponent(_part, out BodyPartComponent? partComp) && partComp.Body is { } Body && _part is { } Part && _system.IsSurgeryValid(Body, Part, requirementId, surgeryId, out _, out _, out _)) + { + var label = new ChoiceControl(); + label.Button.OnPressed += _ => + { + _previousSurgeries.Add(surgeryId); - if (_entities.TryGetComponent(requirement, out SurgeryComponent? requirementComp)) - OnSurgeryPressed((requirement, requirementComp), netPart, requirementId); - }; + 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); + 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) }); + _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) @@ -354,6 +364,12 @@ public sealed class SurgeryBui : BoundUserInterface case StepInvalidReason.MissingTool: stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-tool")); break; + case StepInvalidReason.DisabledTool: + stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-enable")); + break; + case StepInvalidReason.TooHigh: + stepName.AddMarkupOrThrow(Loc.GetString("surgery-window-too-high")); + break; } } } @@ -369,22 +385,21 @@ public sealed class SurgeryBui : BoundUserInterface if (_window == null) return; - if (_system.IsLyingDown(Owner)) - { - _window.DisabledPanel.Visible = false; - _window.DisabledPanel.MouseFilter = MouseFilterMode.Ignore; - return; - } + _window.DisabledPanel.Visible = false; + _window.DisabledPanel.MouseFilter = MouseFilterMode.Ignore; + return; - _window.DisabledPanel.Visible = true; - if (_window.DisabledLabel.GetMessage() is null) + if (!_system.IsLyingDown(Owner)) { - var text = new FormattedMessage(); - text.AddMarkupOrThrow(Loc.GetString("surgery-window-reguires-laydown")); - _window.DisabledLabel.SetMessage(text); + _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; } - - _window.DisabledPanel.MouseFilter = MouseFilterMode.Stop; } private void View(ViewType type) @@ -437,7 +452,6 @@ public sealed class SurgeryBui : BoundUserInterface if (disposing) _window?.Dispose(); - _system.OnRefresh -= UpdateDisabledPanel; _hands.OnPlayerItemAdded -= OnPlayerItemAdded; } } diff --git a/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs index 7bbc2785fb..1db3506a1f 100644 --- a/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs +++ b/Content.Client/_Sunrise/Medical/Surgery/SurgeryStepButton.xaml.cs @@ -1,6 +1,6 @@ -using Content.Client._Sunrise.Choice; -using Robust.Client.AutoGenerated; +using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; +using Content.Client._Sunrise.Choice; namespace Content.Client._Sunrise.Medical.Surgery; // Based on the RMC14. diff --git a/Content.Server/_Sunrise/Medical/LimbDamageSystem.cs b/Content.Server/_Sunrise/Medical/LimbDamageSystem.cs new file mode 100644 index 0000000000..5881769b31 --- /dev/null +++ b/Content.Server/_Sunrise/Medical/LimbDamageSystem.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Content.Server.Body.Systems; +using Content.Server.Hands.Systems; +using Content.Server._Sunrise.Medical.Surgery; +using Content.Shared._Sunrise.Medical.Damage; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.Damage; +using Content.Shared.Hands.Components; +using Content.Shared.Humanoid; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Components; +using Content.Shared.NukeOps; +using Content.Shared.Random.Helpers; +using Content.Shared._Sunrise.Medical.Surgery; +using Content.Shared._Sunrise.Medical.Surgery.Effects.Step; +using Robust.Server.Containers; +using Robust.Shared.Localization; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server._Sunrise.Medical; +public sealed class LimbDamageSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _rand = default!; + [Dependency] private readonly BodySystem _body = default!; + [Dependency] private readonly ContainerSystem _containers = default!; + [Dependency] private readonly HandsSystem _hands = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnDamage); + } + //duct tape solution + private void OnDamage(Entity ent, ref DamageBeforeApplyEvent args) + { + if (HasComp(ent)) return; // Nuke Ops are immune to limb damage. Temporary solution. mb Deathsquad? + if (!TryComp(ent, out var appr) || appr.Species == "SlimePerson") return; // SlimePeople are immune to limb damage. + + var chance = 0f; + foreach (var damage in args.Damage.DamageDict.Where(x => x.Value > 0)) + switch (damage.Key) + { + case "Blunt": + chance += 0.00005f * damage.Value.Float(); + break; + case "Slash": + chance += 0.0005f * damage.Value.Float(); + break; + case "Piercing": + chance += 0.0001f * damage.Value.Float(); + break; + case "Heat": + chance += 0.0002f * damage.Value.Float(); + break; + case "Cold": + chance += 0.0004f * damage.Value.Float(); + break; + case "Caustic": + chance += 0.001f * damage.Value.Float(); + break; + default: + break; + } + chance = Math.Clamp(chance, 0, 1); + if (_rand.Prob(chance)) + { + if (!TryRemoveLimb(ent, out var part)) return; + Dirty(ent); + QueueDel(part.Value.Owner); + args.Cancelled = true; + } + } + + private bool TryRemoveLimb(Entity ent, [NotNullWhen(true)] out Entity? part) + { + part = null; + var root = _body.GetRootPartOrNull(ent.Owner); + if (root is null) return false; + var parts = _body.GetAllBodyPart(root.Value.Entity, root.Value.BodyPart) + .Where(p => p.Comp.PartType != BodyPartType.Head) + .ToList(); + if (parts.Count == 0) return false; + part = _rand.Pick(parts); + var parentPartAndSlot = _body.GetParentPartAndSlotOrNull(part.Value.Owner); + if (parentPartAndSlot is null) return false; + var (_, slotId) = parentPartAndSlot.Value; + + if (!_containers.TryGetContainingContainer((part.Value.Owner, null, null), out var container)) return false; + if (!_containers.Remove(part.Value.Owner, container)) return false; + if (TryComp(part.Value.Owner, out var virtualLimb) + && virtualLimb.Item.HasValue) + { + RemoveItemHand(ent.Owner, virtualLimb.Item.Value, BodySystem.GetPartSlotContainerId(slotId)); + + var vizualizer = EnsureComp(ent.Owner); + + var layer = SurgerySystem.GetLayer(slotId); + if (layer is not null) + { + vizualizer.Layers.Remove(layer.Value); + Dirty(ent.Owner, vizualizer); + } + } + else + { + switch (part.Value.Comp.PartType) + { + case BodyPartType.Arm: //todo move to systems + foreach (var limbSlotId in part.Value.Comp.Children.Keys) + { + if (limbSlotId is null) continue; + var child = _containers.GetContainer(part.Value.Owner, BodySystem.GetPartSlotContainerId(limbSlotId)); + + foreach (var containedEnt in child.ContainedEntities) + { + if (TryComp(containedEnt, out BodyPartComponent? innerPart) + && innerPart.PartType == BodyPartType.Hand) + _hands.RemoveHand(ent.Owner, BodySystem.GetPartSlotContainerId(limbSlotId)); + } + } + break; + case BodyPartType.Hand: + var parentSlot = _body.GetParentPartAndSlotOrNull(part.Value.Owner); + if (parentSlot is not null) + _hands.RemoveHand(ent.Owner, BodySystem.GetPartSlotContainerId(parentSlot.Value.Slot)); + break; + case BodyPartType.Leg: + case BodyPartType.Foot: + break; + } + } + return true; + } + + private void RemoveItemHand(EntityUid bodyId, EntityUid itemId, string handId) + { + if (!TryComp(bodyId, out var hands) + || !_hands.TryGetHand(bodyId, handId, out var hand, hands)) + return; + + if (!itemId.IsValid()) + { + Log.Debug("no valid item"); + return; + } + RemComp(itemId); + _hands.DoDrop(itemId, hand); + _hands.RemoveHand(bodyId, handId, hands); + } +} diff --git a/Content.Server/_Sunrise/Medical/Surgery/OrganSystem.cs b/Content.Server/_Sunrise/Medical/Surgery/OrganSystem.cs new file mode 100644 index 0000000000..977ab9080d --- /dev/null +++ b/Content.Server/_Sunrise/Medical/Surgery/OrganSystem.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Content.Server.Humanoid; +using Content.Shared.Damage; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Eye.Blinding.Systems; +using Content.Shared.Interaction; +using Content.Shared.Speech.Muting; +using Content.Shared._Sunrise.Antags.Abductor; +using Content.Shared._Sunrise.Medical.Surgery.Effects.Step; +using Content.Shared._Sunrise.Medical.Surgery.Events; +using Content.Shared._Sunrise.Medical.Surgery.Steps.Parts; +using Content.Shared._Sunrise.VentCraw; +using Robust.Shared.Prototypes; + +namespace Content.Server._Sunrise.Medical.Surgery; +public sealed partial class OrganSystem : EntitySystem +{ + + [Dependency] private readonly BlindableSystem _blindable = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly IComponentFactory _compFactory = default!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearanceSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnFunctionalOrganImplanted); + SubscribeLocalEvent(OnFunctionalOrganExtracted); + + SubscribeLocalEvent(OnEyeImplanted); + SubscribeLocalEvent(OnEyeExtracted); + + SubscribeLocalEvent(OnTongueImplanted); + SubscribeLocalEvent(OnTongueExtracted); + + SubscribeLocalEvent(OnAbductorOrganImplanted); + SubscribeLocalEvent(OnAbductorOrganExtracted); + + SubscribeLocalEvent(OnOrganImplanted); + SubscribeLocalEvent(OnOrganExtracted); + + SubscribeLocalEvent(OnVisualizationImplanted); + SubscribeLocalEvent(OnVisualizationExtracted); + } + + // + + private void OnFunctionalOrganImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + foreach (var comp in (ent.Comp.Components ?? []).Values) + if (!EntityManager.HasComponent(args.Body, comp.Component.GetType())) + EntityManager.AddComponent(args.Body, _compFactory.GetComponent(comp.Component.GetType())); + } + + private void OnFunctionalOrganExtracted(Entity ent, ref SurgeryOrganExtracted args) + { + foreach (var comp in (ent.Comp.Components ?? []).Values) + if (EntityManager.HasComponent(args.Body, comp.Component.GetType())) + EntityManager.RemoveComponent(args.Body, _compFactory.GetComponent(comp.Component.GetType())); + } + + // + + private void OnOrganImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + if (!TryComp(args.Body, out var bodyDamageable)) return; + + var change = _damageableSystem.TryChangeDamage(args.Body, ent.Comp.Damage, true, false, bodyDamageable); + if (change is not null) + _damageableSystem.TryChangeDamage(ent.Owner, change.Invert(), true, false, ent.Comp); + } + private void OnOrganExtracted(Entity ent, ref SurgeryOrganExtracted args) + { + if (!TryComp(ent.Owner, out var damageRule) + || damageRule.Damage is null + || !TryComp(args.Body, out var bodyDamageable)) return; + + var change = _damageableSystem.TryChangeDamage(args.Body, damageRule.Damage.Invert(), true, false, bodyDamageable); + if (change is not null) + _damageableSystem.TryChangeDamage(ent.Owner, change.Invert(), true, false, ent.Comp); + } + + // + + private void OnAbductorOrganImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + if (TryComp(args.Body, out var victim)) + victim.Organ = ent.Comp.Organ; + if (ent.Comp.Organ == AbductorOrganType.Vent) + AddComp(args.Body); + } + private void OnAbductorOrganExtracted(Entity ent, ref SurgeryOrganExtracted args) + { + if (TryComp(args.Body, out var victim)) + if (victim.Organ == ent.Comp.Organ) + victim.Organ = AbductorOrganType.None; + + if (ent.Comp.Organ == AbductorOrganType.Vent) + RemComp(args.Body); + } + + // + + private void OnTongueImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + if (HasComp(args.Body) || !ent.Comp.IsMuted) return; + RemComp(args.Body); + } + + private void OnTongueExtracted(Entity ent, ref SurgeryOrganExtracted args) + { + ent.Comp.IsMuted = HasComp(args.Body); + AddComp(args.Body); + } + + // + + private void OnEyeExtracted(Entity ent, ref SurgeryOrganExtracted args) + { + if (!TryComp(args.Body, out var blindable)) return; + + ent.Comp.EyeDamage = blindable.EyeDamage; + ent.Comp.MinDamage = blindable.MinDamage; + _blindable.UpdateIsBlind((args.Body, blindable)); + } + private void OnEyeImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + if (!TryComp(args.Body, out var blindable)) return; + + _blindable.SetMinDamage((args.Body, blindable), ent.Comp.MinDamage ?? 0); + _blindable.AdjustEyeDamage((args.Body, blindable), (ent.Comp.EyeDamage ?? 0) - blindable.MaxDamage); + } + + // + + private void OnVisualizationExtracted(Entity ent, ref SurgeryOrganExtracted args) + => _humanoidAppearanceSystem.SetLayersVisibility(args.Body, [ent.Comp.Layer], false); + private void OnVisualizationImplanted(Entity ent, ref SurgeryOrganImplantationCompleted args) + { + _humanoidAppearanceSystem.SetLayersVisibility(args.Body, [ent.Comp.Layer], true); + _humanoidAppearanceSystem.SetBaseLayerId(args.Body, ent.Comp.Layer, ent.Comp.Prototype); + } +} diff --git a/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.Steps.cs b/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.Steps.cs index 688b40bdc0..0748011b7d 100644 --- a/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.Steps.cs +++ b/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.Steps.cs @@ -7,8 +7,8 @@ using Content.Shared._Sunrise.Medical.Surgery.Steps.Parts; using Content.Shared.Body.Components; using Content.Shared.Body.Organ; using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Hands.Components; using Content.Shared.Speech.Muting; @@ -16,12 +16,21 @@ using Robust.Shared.Prototypes; using Content.Shared.Humanoid; using Content.Shared._Sunrise; using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Interaction.Components; +using Microsoft.CodeAnalysis; namespace Content.Server._Sunrise.Medical.Surgery; // Based on the RMC14. // https://github.com/RMC-14/RMC-14 +// +//This file is already overloaded with responsibilities, +//it’s time to break its functionality into different systems. +//However, I don’t want to touch the official systems, so I need to come up with extensions for them. public sealed partial class SurgerySystem : SharedSurgerySystem { + [Dependency] private readonly IComponentFactory _compFactory = default!; + + private readonly EntProtoId _virtual = "PartVirtual"; public void InitializeSteps() { SubscribeLocalEvent(OnStepBleedComplete); @@ -32,16 +41,29 @@ public sealed partial class SurgerySystem : SharedSurgerySystem SubscribeLocalEvent(OnStepOrganExtractComplete); SubscribeLocalEvent(OnStepOrganInsertComplete); - SubscribeLocalEvent(OnStepAttachLimbComplete); + SubscribeLocalEvent(OnStepAttachComplete); SubscribeLocalEvent(OnStepAmputationComplete); + SubscribeLocalEvent(CustomLimbRemoved); + SubscribeLocalEvent(OnRemoveAccent); } + private void OnStepAttachComplete(Entity ent, ref SurgeryStepEvent args) + { + if (GetSingleton(args.SurgeryProto) is not { } surgery + || !TryComp(surgery, out var slotComp)) + return; + + OnStepAttachLimbComplete(ent, slotComp.Slot, ref args); + if (slotComp.Slot != "head") + OnStepAttachItemComplete(ent, slotComp.Slot, ref args); + } + private void OnStepBleedComplete(Entity ent, ref SurgeryStepEvent args) { - if(ent.Comp.Damage is not null && TryComp(args.Body, out var comp)) + if (ent.Comp.Damage is not null && TryComp(args.Body, out var comp)) _damageableSystem.TryChangeDamage(args.Body, ent.Comp.Damage); //todo add wound } @@ -54,8 +76,18 @@ public sealed partial class SurgerySystem : SharedSurgerySystem { if (args.Tools.Count == 0 || !(args.Tools.FirstOrDefault() is var organId) - || !TryComp(args.Part, out var bodyPart) - || !TryComp(organId, out var organComp)) + || !TryComp(args.Part, out var bodyPart)) + return; + + var containerId = SharedBodySystem.GetOrganContainerId(ent.Comp.Slot); + + if (ent.Comp.Slot == "cavity" && _containers.TryGetContainer(args.Part, containerId, out var container)) + { + _containers.Insert(organId, container); + return; + } + + if (!TryComp(organId, out var organComp)) return; var part = args.Part; @@ -63,59 +95,36 @@ public sealed partial class SurgerySystem : SharedSurgerySystem _delayAccumulator = 0; _delayQueue.Enqueue(() => { - if (_body.InsertOrgan(part, organId, ent.Comp.Slot, bodyPart, organComp) - && TryComp(organId, out var organDamageable) - && TryComp(body, out var bodyDamageable)) - { - if (TryComp(organId, out var organEyes) - && TryComp(body, out var blindable)) - { - _blindable.SetMinDamage((body, blindable), organEyes.MinDamage ?? 0); - _blindable.AdjustEyeDamage((body, blindable), (organEyes.EyeDamage ?? 0) - blindable.MaxDamage); - } - if (TryComp(organId, out var organTongue) - && !organTongue.IsMuted) - RemComp(body); + if (!_body.InsertOrgan(part, organId, ent.Comp.Slot, bodyPart, organComp)) return; - var change = _damageableSystem.TryChangeDamage(body, organDamageable.Damage, true, false, bodyDamageable); - if (change is not null) - _damageableSystem.TryChangeDamage(organId, change.Invert(), true, false, organDamageable); - } + var ev = new SurgeryOrganImplantationCompleted(body, part, organId); + RaiseLocalEvent(organId, ref ev); }); } private void OnStepOrganExtractComplete(Entity ent, ref SurgeryStepEvent args) { if (ent.Comp.Organ?.Count != 1) return; - var organs = _body.GetPartOrgans(args.Part, Comp(args.Part)); + var type = ent.Comp.Organ.Values.First().Component.GetType(); + + if (ent.Comp.Slot != null && _containers.TryGetContainer(args.Part, SharedBodySystem.GetOrganContainerId(ent.Comp.Slot), out var container)) + { + foreach (var containedEnt in container.ContainedEntities) + if (HasComp(containedEnt, type)) + _containers.Remove(containedEnt, container); + + return; + } + + var organs = _body.GetPartOrgans(args.Part, Comp(args.Part)); foreach (var organ in organs) { - if (HasComp(organ.Id, type)) - { - if (_body.RemoveOrgan(organ.Id, organ.Component) - && TryComp(organ.Id, out var damageRule) - && damageRule.Damage is not null - && TryComp(organ.Id, out var organDamageable) - && TryComp(args.Body, out var bodyDamageable)) - { - if (TryComp(organ.Id, out var organEyes) - && TryComp(args.Body, out var blindable)) - { - organEyes.EyeDamage = blindable.EyeDamage; - organEyes.MinDamage = blindable.MinDamage; - _blindable.UpdateIsBlind((args.Body, blindable)); - } - if (TryComp(organ.Id, out var organTongue)) - { - organTongue.IsMuted = HasComp(args.Body); - AddComp(args.Body); - } - var change = _damageableSystem.TryChangeDamage(args.Body, damageRule.Damage.Invert(), true, false, bodyDamageable); - if (change is not null) - _damageableSystem.TryChangeDamage(organ.Id, change.Invert(), true, false, organDamageable); - } - return; - } + if (!HasComp(organ.Id, type) || !_body.RemoveOrgan(organ.Id, organ.Component)) continue; + + var ev = new SurgeryOrganExtracted(args.Body, args.Part, organ.Id); + RaiseLocalEvent(organ.Id, ref ev); + + return; } } @@ -133,7 +142,7 @@ public sealed partial class SurgerySystem : SharedSurgerySystem if (TryComp(args.Body, out TransformComponent? xform)) SpawnAtPosition(ent.Comp.Entity, xform.Coordinates); } - private void OnStepAttachLimbComplete(Entity ent, ref SurgeryStepEvent args) + private void OnStepAttachLimbComplete(Entity _, string slot, ref SurgeryStepEvent args) { if (args.Tools.Count == 0 || !(args.Tools.FirstOrDefault() is var limbId) @@ -144,61 +153,130 @@ public sealed partial class SurgerySystem : SharedSurgerySystem var part = args.Part; var body = args.Body; - _delayAccumulator = 0; - _delayQueue.Enqueue(() => + if (!_body.AttachPart(part, slot, limbId, bodyPart, limb)) { - var slot = ""; - foreach (var slotTemp in _body.TryGetFreePartSlots(part, bodyPart)) - { - slot = slotTemp; - if (_body.AttachPart(part, slot, limbId, bodyPart, limb)) - break; - } + args.IsCancelled = true; + return; + } - if (TryComp(body, out var humanoid)) //todo move to system + if (TryComp(body, out var humanoid)) //todo move to system + { + var limbs = _body.GetBodyPartAdjacentParts(limbId, limb).Except([part]).Concat([limbId]); + foreach (var partLimbId in limbs) { - var limbs = _body.GetBodyPartAdjacentParts(limbId, limb).Except([part]).Concat([limbId]); - foreach (var partLimbId in limbs) + if (TryComp(partLimbId, out var baseLayerStorage) + && TryComp(partLimbId, out BodyPartComponent? partLimb)) { - if (TryComp(partLimbId, out var baseLayerStorage) - && TryComp(partLimbId, out BodyPartComponent? partLimb)) - { - var layer = partLimb.ToHumanoidLayers(); - if (layer is null) continue; - _humanoidAppearanceSystem.SetBaseLayerId(body, layer.Value, baseLayerStorage.Layer, true, humanoid); - } + var layer = partLimb.ToHumanoidLayers(); + if (layer is null) continue; + _humanoidAppearanceSystem.SetBaseLayerId(body, layer.Value, baseLayerStorage.Layer, true, humanoid); } } - switch (limb.PartType) - { - case BodyPartType.Arm: //todo move to systems - if (limb.Children.Keys.Count == 0) - { - _body.TryCreatePartSlot(limbId, limb.Symmetry == BodyPartSymmetry.Left ? "left hand" : "right hand", BodyPartType.Hand, out var slotId); - } - foreach (var slotId in limb.Children.Keys) - { - if (slotId is null) continue; - var slotFullId = BodySystem.GetPartSlotContainerId(slotId); - var child = _containers.GetContainer(limbId, slotFullId); + } - foreach (var containedEnt in child.ContainedEntities) - { - if (TryComp(containedEnt, out BodyPartComponent? innerPart) - && innerPart.PartType == BodyPartType.Hand) - _hands.AddHand(body, slotFullId, limb.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right); - } + switch (limb.PartType) + { + case BodyPartType.Arm: //todo move to systems + if (limb.Children.Keys.Count == 0) + _body.TryCreatePartSlot(limbId, limb.Symmetry == BodyPartSymmetry.Left ? "left hand" : "right hand", BodyPartType.Hand, out var slotId); + + foreach (var slotId in limb.Children.Keys) + { + if (slotId is null) continue; + var slotFullId = BodySystem.GetPartSlotContainerId(slotId); + var child = _containers.GetContainer(limbId, slotFullId); + + foreach (var containedEnt in child.ContainedEntities) + { + if (TryComp(containedEnt, out BodyPartComponent? innerPart) + && innerPart.PartType == BodyPartType.Hand) + _hands.AddHand(body, slotFullId, limb.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right); } - break; - case BodyPartType.Hand: - _hands.AddHand(body, BodySystem.GetPartSlotContainerId(slot), limb.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right); - break; - case BodyPartType.Leg: - case BodyPartType.Foot: - break; - } - }); + } + break; + case BodyPartType.Hand: + _hands.AddHand(body, BodySystem.GetPartSlotContainerId(slot), limb.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right); + break; + case BodyPartType.Leg: + if (limb.Children.Keys.Count == 0) + _body.TryCreatePartSlot(limbId, limb.Symmetry == BodyPartSymmetry.Left ? "left foot" : "right foot", BodyPartType.Foot, out var slotId); + break; + case BodyPartType.Foot: + break; + } } + + private void OnStepAttachItemComplete(Entity ent, string slot, ref SurgeryStepEvent args) + { + if (args.Tools.Count == 0 + || !(args.Tools.FirstOrDefault() is var itemId) + || !TryComp(args.Part, out var bodyPart) + || !TryComp(itemId, out MetaDataComponent? metada) + || TryComp(itemId, out var _) + || Prototype(itemId) is not EntityPrototype prototype) + return; + + var marker = EnsureComp(itemId); + + var virtualIteam = Spawn(_virtual); + var virtualBodyPart = EnsureComp(virtualIteam); + var virtualMetadata = EnsureComp(virtualIteam); + var virtualCustomLimb = EnsureComp(virtualIteam); + _metadata.SetEntityName(virtualIteam, metada.EntityName, virtualMetadata); + + marker.VirtualPart = virtualIteam; + virtualCustomLimb.Item = itemId; + + virtualBodyPart.PartType = slot switch + { + "left arm" => BodyPartType.Arm, + "right arm" => BodyPartType.Arm, + "left hand" => BodyPartType.Hand, + "right hand" => BodyPartType.Hand, + "left leg" => BodyPartType.Leg, + "right leg" => BodyPartType.Leg, + "left foot" => BodyPartType.Foot, + "right foot" => BodyPartType.Foot, + "tail" => BodyPartType.Tail, + _ => BodyPartType.Other, + }; + if (!_body.AttachPart(args.Part, slot, virtualIteam, bodyPart, virtualBodyPart)) + { + args.IsCancelled = true; + QueueDel(virtualIteam); + return; + } + + if (TryComp(args.Body, out var humanoid)) //todo move to system + { + var layer = GetLayer(slot); + if (layer is null) + return; + + var vizualizer = EnsureComp(args.Body); + vizualizer.Layers[layer.Value] = GetNetEntity(itemId); + Dirty(args.Body, vizualizer); + + } + AddItemHand(args.Body, itemId, BodySystem.GetPartSlotContainerId(slot)); + } + + private void AddItemHand(EntityUid bodyId, EntityUid itemId, string handId) + { + if (!TryComp(bodyId, out var hands)) + return; + + if (!itemId.IsValid()) + { + Log.Debug("no valid item"); + return; + } + + _hands.AddHand(bodyId, handId, HandLocation.Middle, hands); + _hands.DoPickup(bodyId, hands.Hands[handId], itemId, hands); + EnsureComp(itemId); + } + private void OnStepAmputationComplete(Entity ent, ref SurgeryStepEvent args) { if (TryComp(args.Body, out TransformComponent? xform) @@ -207,55 +285,114 @@ public sealed partial class SurgerySystem : SharedSurgerySystem { if (!_containers.TryGetContainingContainer((args.Part, null, null), out var container)) return; + + var parentPartAndSlot = _body.GetParentPartAndSlotOrNull(args.Part); + if (parentPartAndSlot is null) return; + var (_, slotId) = parentPartAndSlot.Value; + if (_containers.Remove(args.Part, container, destination: xform.Coordinates)) { - if (TryComp(args.Body, out var humanoid)) //todo move to system + if (TryComp(args.Part, out var virtualLimb) + && virtualLimb.Item.HasValue) { - var limbs = _body.GetBodyPartAdjacentParts(args.Part, limb).Concat([args.Part]); ; - foreach (var partLimbId in limbs) + RemoveItemHand(args.Body, virtualLimb.Item.Value, BodySystem.GetPartSlotContainerId(slotId)); + + var vizualizer = EnsureComp(args.Body); + + var layer = GetLayer(slotId); + if (layer is not null) { - if (TryComp(partLimbId, out var baseLayerStorage) - && TryComp(partLimbId, out BodyPartComponent? partLimb)) + vizualizer.Layers.Remove(layer.Value); + Dirty(args.Body, vizualizer); + } + QueueDel(args.Part); + } + else + { + if (TryComp(args.Body, out var humanoid)) //todo move to system + { + var limbs = _body.GetBodyPartAdjacentParts(args.Part, limb).Concat([args.Part]); ; + foreach (var partLimbId in limbs) { - var layer = partLimb.ToHumanoidLayers(); - if (layer is null) continue; - if (humanoid.CustomBaseLayers.TryGetValue(layer.Value, out var customBaseLayer)) - baseLayerStorage.Layer = customBaseLayer.Id; - else + if (TryComp(partLimbId, out var baseLayerStorage) + && TryComp(partLimbId, out BodyPartComponent? partLimb)) { - var bodyType = _prototypes.Index(humanoid.BodyType); - if (bodyType.Sprites.TryGetValue(layer.Value, out var baseLayer)) - baseLayerStorage.Layer = baseLayer; + var layer = partLimb.ToHumanoidLayers(); + if (layer is null) continue; + if (humanoid.CustomBaseLayers.TryGetValue(layer.Value, out var customBaseLayer)) + baseLayerStorage.Layer = customBaseLayer.Id; + else + { + var bodyType = _prototypes.Index(humanoid.BodyType); + if (bodyType.Sprites.TryGetValue(layer.Value, out var baseLayer)) + baseLayerStorage.Layer = baseLayer; + } } } } - } - switch (limb.PartType) - { - case BodyPartType.Arm: //todo move to systems - foreach (var slotId in limb.Children.Keys) - { - if (slotId is null) continue; - var child = _containers.GetContainer(args.Part, BodySystem.GetPartSlotContainerId(slotId)); - - foreach (var containedEnt in child.ContainedEntities) + switch (limb.PartType) + { + case BodyPartType.Arm: //todo move to systems + foreach (var limbSlotId in limb.Children.Keys) { - if (TryComp(containedEnt, out BodyPartComponent? innerPart) - && innerPart.PartType == BodyPartType.Hand) - _hands.RemoveHand(args.Body, BodySystem.GetPartSlotContainerId(slotId)); + if (limbSlotId is null) continue; + var child = _containers.GetContainer(args.Part, BodySystem.GetPartSlotContainerId(limbSlotId)); + + foreach (var containedEnt in child.ContainedEntities) + { + if (TryComp(containedEnt, out BodyPartComponent? innerPart) + && innerPart.PartType == BodyPartType.Hand) + _hands.RemoveHand(args.Body, BodySystem.GetPartSlotContainerId(limbSlotId)); + } } - } - break; - case BodyPartType.Hand: - var parentSlot = _body.GetParentPartAndSlotOrNull(args.Part); - if (parentSlot is not null) - _hands.RemoveHand(args.Body, BodySystem.GetPartSlotContainerId(parentSlot.Value.Slot)); - break; - case BodyPartType.Leg: - case BodyPartType.Foot: - break; + break; + case BodyPartType.Hand: + var parentSlot = _body.GetParentPartAndSlotOrNull(args.Part); + if (parentSlot is not null) + _hands.RemoveHand(args.Body, BodySystem.GetPartSlotContainerId(parentSlot.Value.Slot)); + break; + case BodyPartType.Leg: + case BodyPartType.Foot: + break; + } } } } } + private void RemoveItemHand(EntityUid bodyId, EntityUid itemId, string handId) + { + if (!TryComp(bodyId, out var hands) + || !_hands.TryGetHand(bodyId, handId, out var hand, hands)) + return; + + if (!itemId.IsValid()) + { + Log.Debug("no valid item"); + return; + } + RemComp(itemId); + _hands.DoDrop(itemId, hand); + _hands.RemoveHand(bodyId, handId, hands); + } + + private void CustomLimbRemoved(Entity ent, ref ComponentRemove args) + { + if (ent.Comp.VirtualPart is null) return; + QueueDel(ent.Comp.VirtualPart.Value); + } + + public static HumanoidVisualLayers? GetLayer(string slotId) => slotId switch + { + "left arm" => HumanoidVisualLayers.LArm, + "right arm" => HumanoidVisualLayers.RArm, + "left hand" => HumanoidVisualLayers.LHand, + "right hand" => HumanoidVisualLayers.RHand, + "left leg" => HumanoidVisualLayers.LLeg, + "right leg" => HumanoidVisualLayers.RLeg, + "left foot" => HumanoidVisualLayers.LFoot, + "right foot" => HumanoidVisualLayers.RFoot, + "tail" => HumanoidVisualLayers.Tail, + _ => null, + }; + } diff --git a/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.cs b/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.cs index b2182f87f8..db96482883 100644 --- a/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.cs +++ b/Content.Server/_Sunrise/Medical/Surgery/SurgerySystem.cs @@ -1,8 +1,10 @@ -using Content.Server.Body.Systems; +using System.Linq; +using Content.Server.Body.Systems; using Content.Server.Chat.Systems; using Content.Server.Hands.Systems; using Content.Server.Humanoid; using Content.Server.Popups; +using Content.Shared.Body.Part; using Content.Shared._Sunrise.Medical.Surgery; using Content.Shared._Sunrise.Medical.Surgery.Effects.Step; using Content.Shared._Sunrise.Medical.Surgery.Events; @@ -11,6 +13,7 @@ using Content.Shared.Eye.Blinding.Systems; using Content.Shared.HealthExaminable; using Content.Shared.Interaction; using Content.Shared.Prototypes; +using Content.Shared.Tag; using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Prototypes; @@ -31,6 +34,8 @@ public sealed partial class SurgerySystem : SharedSurgerySystem [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly ContainerSystem _containers = default!; [Dependency] private readonly BlindableSystem _blindable = default!; + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly MetaDataSystem _metadata = default!; private readonly List _surgeries = []; public override void Initialize() @@ -61,40 +66,52 @@ public sealed partial class SurgerySystem : SharedSurgerySystem return; var surgeries = new Dictionary>(); - foreach (var part in _body.GetBodyChildren(body)) + if (HasComp(body)) { - if (!TryComp(part.Id, out var progress)) + AddSurgeries(body, body, surgeries); + } + else + { + foreach (var part in _body.GetBodyChildren(body)) { - progress = new SurgeryProgressComponent(); - AddComp(part.Id, progress); - } - - foreach (var surgery in _surgeries) - { - if (GetSingleton(surgery) is not { } surgeryEnt - || !TryComp(surgeryEnt, out SurgeryComponent? surgeryComp) - || (surgeryComp.Requirement is not null && !progress.CompletedSurgeries.Contains(surgeryComp.Requirement.Value))) - continue; - - var ev = new SurgeryValidEvent(body, part.Id); - - var isCompleted = progress.CompletedSurgeries.Contains(surgery); - if (!progress.StartedSurgeries.Contains(surgery) - && !isCompleted) - { - RaiseLocalEvent(surgeryEnt, ref ev); - - if (ev.Cancelled) - continue; - } - - surgeries.GetOrNew(GetNetEntity(part.Id)).Add((surgery, ev.Suffix, isCompleted)); + AddSurgeries(part.Id, body, surgeries); } } _ui.SetUiState(body, SurgeryUIKey.Key, new SurgeryBuiState() { Choices = surgeries }); } + private void AddSurgeries(EntityUid part, EntityUid body, Dictionary> surgeries) + { + if (!TryComp(part, out var progress)) + { + progress = new SurgeryProgressComponent(); + AddComp(part, progress); + } + + foreach (var surgery in _surgeries) + { + if (GetSingleton(surgery) is not { } surgeryEnt + || !TryComp(surgeryEnt, out SurgeryComponent? surgeryComp) + || (surgeryComp.Requirement.Count() > 0 && !progress.CompletedSurgeries.Any(x => surgeryComp.Requirement.Contains(x)))) + continue; + + var ev = new SurgeryValidEvent(body, part); + + var isCompleted = progress.CompletedSurgeries.Contains(surgery); + if (!progress.StartedSurgeries.Contains(surgery) + && !isCompleted) + { + RaiseLocalEvent(surgeryEnt, ref ev); + + if (ev.Cancelled) + continue; + } + + surgeries.GetOrNew(GetNetEntity(part)).Add((surgery, ev.Suffix, isCompleted)); + } + } + private void OnToolAfterInteract(Entity ent, ref AfterInteractEvent args) { var user = args.User; @@ -106,7 +123,7 @@ public sealed partial class SurgerySystem : SharedSurgerySystem if (user == args.Target) { - _popup.PopupEntity("You can't perform surgery on yourself!", user, user); + _popup.PopupEntity(Loc.GetString("cant-perform-operation-on-yourself"), user, user); return; } diff --git a/Content.Shared/Body/Part/BodyPartComponent.cs b/Content.Shared/Body/Part/BodyPartComponent.cs index 34c68159b1..1b5c574862 100644 --- a/Content.Shared/Body/Part/BodyPartComponent.cs +++ b/Content.Shared/Body/Part/BodyPartComponent.cs @@ -3,11 +3,12 @@ using Content.Shared.Body.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Serialization; +using Content.Shared._Sunrise.Medical.Surgery; namespace Content.Shared.Body.Part; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedBodySystem))] +[Access(typeof(SharedBodySystem), typeof(SharedSurgerySystem))] // Sunrise-edit public sealed partial class BodyPartComponent : Component { // Need to set this on container changes as it may be several transform parents up the hierarchy. diff --git a/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs b/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs index 338e6c8ab8..e654ee1ee6 100644 --- a/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs +++ b/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs @@ -40,11 +40,23 @@ public sealed class BodyPrototypeSerializer : ITypeReader> GetAllBodyPart( + EntityUid partId, + BodyPartComponent? part = null) + { + if (!Resolve(partId, ref part, logMissing: false)) + yield break; + + foreach (var (slotId, slot) in part.Children) + { + var containerSlotId = GetPartSlotContainerId(slotId); + + if (Containers.TryGetContainer(partId, containerSlotId, out var container)) + { + foreach (var containedEnt in container.ContainedEntities) + { + if (!TryComp(containedEnt, out BodyPartComponent? childPart)) + continue; + yield return (containedEnt, childPart); + + foreach (var subPart in GetAllBodyPart(containedEnt, childPart)) + { + yield return subPart; + } + } + } + } + } + // Sunrise-End + /// /// Returns true if the bodyId has any parts of this type. diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 04f11fba62..1b250a1127 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -18,6 +18,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using Robust.Shared.Configuration; using Robust.Shared.Random; +using Content.Shared._Sunrise.Medical.Damage; namespace Content.Shared.Damage { @@ -239,6 +240,17 @@ namespace Content.Shared.Damage damage = ApplyUniversalAllModifiers(damage); + // Sunrise-start + var finalEv = new DamageBeforeApplyEvent + { + Damage = damage, + Origin = origin + }; + RaiseLocalEvent(uid.Value, finalEv); + if (finalEv.Cancelled) + return damage; + // Sunrise-end + // TODO DAMAGE PERFORMANCE // Consider using a local private field instead of creating a new dictionary here. // Would need to check that nothing ever tries to cache the delta. diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index 3a5a098f18..43a9ca1d46 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -550,9 +550,12 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem { return; } - - var markingObject = new Marking(marking, colors); - markingObject.Forced = forced; + // Sunrise-start + var markingObject = new Marking(marking, colors) + { + Forced = forced + }; + // Sunrise-end humanoid.MarkingSet.AddBack(prototype.MarkingCategory, markingObject); if (sync) diff --git a/Content.Shared/_Sunrise/Medical/Damage/DamageBeforeApplyEvent.cs b/Content.Shared/_Sunrise/Medical/Damage/DamageBeforeApplyEvent.cs new file mode 100644 index 0000000000..370e07c366 --- /dev/null +++ b/Content.Shared/_Sunrise/Medical/Damage/DamageBeforeApplyEvent.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Content.Shared.Damage; +using Content.Shared.Inventory; + +namespace Content.Shared._Sunrise.Medical.Damage; +public sealed class DamageBeforeApplyEvent : EntityEventArgs +{ + public required DamageSpecifier Damage; + public EntityUid? Origin; + + public bool Cancelled { get; set; } +} diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/CustomLimbVisualizerComponent.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/CustomLimbVisualizerComponent.cs new file mode 100644 index 0000000000..0d6ccc1bfb --- /dev/null +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/CustomLimbVisualizerComponent.cs @@ -0,0 +1,32 @@ +using Content.Shared.DisplacementMap; +using Content.Shared.Humanoid; +using Content.Shared.Item; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +namespace Content.Shared._Sunrise.Medical.Surgery; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class CustomLimbVisualizerComponent : Component +{ + [DataField, AutoNetworkedField] + public Dictionary Layers = []; + + [DataField] + public HashSet CachedLayers = []; + + [DataField] + public Dictionary Displacements = []; +} +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CustomLimbComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? Item; +} +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CustomLimbMarkerComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? VirtualPart; +} diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryComponent.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryComponent.cs index 4dbd62844f..0f7e5a48d7 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryComponent.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryComponent.cs @@ -13,7 +13,7 @@ public sealed partial class SurgeryComponent : Component public int Priority; [DataField, AutoNetworkedField] - public EntProtoId? Requirement; + public List Requirement = []; [DataField(required: true), AutoNetworkedField] public List Steps = new(); diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryProgressComponent.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryProgressComponent.cs index 6143b88973..ae746a141c 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryProgressComponent.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/SurgeryProgressComponent.cs @@ -15,4 +15,4 @@ public sealed partial class SurgeryProgressComponent : Component [DataField, AutoNetworkedField] public HashSet StartedSurgeries = []; -} \ No newline at end of file +} diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Conditions.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Conditions.cs index 8862b60225..c05e6f52ef 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Conditions.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Conditions.cs @@ -1,4 +1,6 @@ using Content.Shared.Body.Part; +using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Item; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; // Based on the RMC14. @@ -9,6 +11,20 @@ namespace Content.Shared._Sunrise.Medical.Surgery.Effects.Step; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryAnyLimbSlotConditionComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryOperatingTableConditionComponent : Component; +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +public sealed partial class SurgeryLimbSlotConditionComponent : Component +{ + [DataField] + public string Slot; +} + +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +public sealed partial class SurgeryItemSizeConditionComponent : Component +{ + [DataField] + public ProtoId Size = "Small"; +} + [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryPartConditionComponent : Component { @@ -16,14 +32,35 @@ public sealed partial class SurgeryPartConditionComponent : Component public List Parts = []; } [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +public sealed partial class SurgerySpeciesConditionComponent : Component +{ + [DataField] + public HashSet> SpeciesBlacklist = []; + + [DataField] + public HashSet> SpeciesWhitelist = []; +} +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryOrganExistConditionComponent : Component { [DataField] public ComponentRegistry? Organ; + + [DataField] + public string? Container; +} +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +public sealed partial class SurgeryHasCompConditionComponent : Component +{ + [DataField] + public ComponentRegistry? Component; } [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryOrganDontExistConditionComponent : Component { [DataField] public ComponentRegistry? Organ; -} \ No newline at end of file + + [DataField] + public string? Container; +} diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Organs.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Organs.cs index f452023292..b22c28f4ca 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Organs.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Organs.cs @@ -1,8 +1,11 @@ -using Content.Shared.Damage; +using Content.Shared.Damage; +using Content.Shared.Humanoid; +using Content.Shared.Humanoid.Prototypes; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; namespace Content.Shared._Sunrise.Medical.Surgery.Steps.Parts; +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class EyeImplantComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganBrainComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganAppendixComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganEarsComponent : Component; @@ -11,14 +14,14 @@ namespace Content.Shared._Sunrise.Medical.Surgery.Steps.Parts; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganStomachComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganLiverComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class OrganKidneysComponent : Component; -[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +[RegisterComponent, NetworkedComponent] public sealed partial class OrganTongueComponent : Component { [DataField] public bool IsMuted; } -[RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +[RegisterComponent, NetworkedComponent] public sealed partial class OrganEyesComponent : Component { [DataField] @@ -26,10 +29,25 @@ public sealed partial class OrganEyesComponent : Component [DataField] public int? MinDamage; } +[RegisterComponent, NetworkedComponent] +public sealed partial class OrganVisualizationComponent : Component +{ + [DataField] + public HumanoidVisualLayers Layer; + [DataField] + public ProtoId Prototype; +} [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] +public sealed partial class FunctionalOrganComponent : Component +{ + [DataField("comps")] + public ComponentRegistry? Components; +} + +[RegisterComponent, NetworkedComponent] public sealed partial class OrganDamageComponent : Component { [DataField] public DamageSpecifier? Damage; -} \ No newline at end of file +} diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Parts.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Parts.cs index 470bd0769b..0ac9a748ea 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Parts.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Parts.cs @@ -12,10 +12,13 @@ public sealed partial class SurgeryStepOrganExtractComponent : Component { [DataField] public ComponentRegistry? Organ; + + [DataField] + public string? Slot; } [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] -public sealed partial class SurgeryStepOrganInsertComponent : Component +public sealed partial class SurgeryStepOrganInsertComponent : Component { [DataField(required: true)] public string Slot; diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Steps.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Steps.cs index 5bc50e3ee6..821ac6cbe9 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Steps.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Steps.cs @@ -12,7 +12,7 @@ namespace Content.Shared._Sunrise.Medical.Surgery.Effects.Step; { [DataField] public DamageSpecifier? Damage; -}; +} [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryStepAmputationEffectComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryRemoveAccentComponent : Component; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSurgerySystem))] public sealed partial class SurgeryClearProgressComponent : Component; diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Tools.cs b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Tools.cs index 2b93c2a6f4..701ced6d17 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Components/_Tools.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Components/_Tools.cs @@ -12,6 +12,9 @@ public sealed partial class SurgeryToolComponent : Component [DataField, AutoNetworkedField] public float Speed = 1; + [DataField, AutoNetworkedField] + public float SuccessRate = 1f; + [DataField, AutoNetworkedField] public SoundSpecifier? StartSound; diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryDoAfterEvent.cs b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryDoAfterEvent.cs index 5d88fcefaa..c60ad827ac 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryDoAfterEvent.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryDoAfterEvent.cs @@ -10,10 +10,12 @@ public sealed partial class SurgeryDoAfterEvent : SimpleDoAfterEvent { public readonly EntProtoId Surgery; public readonly EntProtoId Step; + public readonly float SuccessRate; - public SurgeryDoAfterEvent(EntProtoId surgery, EntProtoId step) + public SurgeryDoAfterEvent(EntProtoId surgery, EntProtoId step, float successRate) { Surgery = surgery; Step = step; + SuccessRate = successRate; } } diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryOrganInsertCompleted.cs b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryOrganInsertCompleted.cs new file mode 100644 index 0000000000..c006ed55e3 --- /dev/null +++ b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryOrganInsertCompleted.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared._Sunrise.Medical.Surgery.Events; +// Based on the RMC14. +// https://github.com/RMC-14/RMC-14 +[ByRefEvent] +public record struct SurgeryOrganImplantationCompleted(EntityUid Body, EntityUid Part, EntityUid Organ); +[ByRefEvent] +public record struct SurgeryOrganExtracted(EntityUid Body, EntityUid Part, EntityUid Organ); diff --git a/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryStepEvent.cs b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryStepEvent.cs index d681970514..0e2caa3f5b 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryStepEvent.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/Events/SurgeryStepEvent.cs @@ -8,6 +8,13 @@ namespace Content.Shared._Sunrise.Medical.Surgery.Events; /// [ByRefEvent] public record struct SurgeryStepEvent(EntityUid User, EntityUid Body, EntityUid Part, List Tools) +{ + public required EntProtoId StepProto { get; init; } + public required EntProtoId SurgeryProto { get; init; } + public bool IsCancelled { get; set; } +} +[ByRefEvent] +public record struct SurgeryStepCompleteEvent(EntityUid User, EntityUid Body, EntityUid Part, List Tools) { public required EntProtoId StepProto { get; init; } public required EntProtoId SurgeryProto { get; init; } diff --git a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.BaseSteps.cs b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.BaseSteps.cs index 671f618446..421cadb327 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.BaseSteps.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.BaseSteps.cs @@ -1,12 +1,15 @@ -using Content.Shared._Sunrise.Medical.Surgery.Steps; -using Content.Shared.Body.Part; +using Content.Shared.Body.Part; using Content.Shared.Buckle.Components; using Content.Shared.DoAfter; using Content.Shared.Inventory; +using Content.Shared.Item; +using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Popups; -using Robust.Shared.Prototypes; -using Content.Shared._Sunrise.Medical.Surgery.Events; using Content.Shared._Sunrise.Medical.Surgery.Effects.Step; +using Content.Shared._Sunrise.Medical.Surgery.Events; +using Content.Shared._Sunrise.Medical.Surgery.Steps; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; using System.Linq; namespace Content.Shared._Sunrise.Medical.Surgery; @@ -14,13 +17,15 @@ namespace Content.Shared._Sunrise.Medical.Surgery; // https://github.com/RMC-14/RMC-14 public abstract partial class SharedSurgerySystem { + [Dependency] private readonly IRobustRandom _random = default!; protected float _delayAccumulator = 0f; protected readonly Queue _delayQueue = new(); private void InitializeSteps() { + SubscribeLocalEvent(OnStepComplete); + SubscribeLocalEvent(OnClearProgressStep); SubscribeLocalEvent(OnStep); - SubscribeLocalEvent(OnClearProgressStep); SubscribeLocalEvent(OnTargetDoAfter); SubscribeLocalEvent(OnCanPerformStep); @@ -43,47 +48,63 @@ public abstract partial class SharedSurgerySystem return; } + if (!_random.Prob(args.SuccessRate)) + { + if (_net.IsClient) return; + _popup.PopupClient(Loc.GetString("surgery-careless-tool"), args.User, PopupType.SmallCaution); + return; + } + var ev = new SurgeryStepEvent(args.User, ent, part, GetTools(args.User)) + { + StepProto = args.Step, + SurgeryProto = args.Surgery, + }; + RaiseLocalEvent(step, ref ev); + + if (ev.IsCancelled) return; + var evComplete = new SurgeryStepCompleteEvent(args.User, ent, part, GetTools(args.User)) { StepProto = args.Step, SurgeryProto = args.Surgery, IsFinal = surgery.Comp.Steps[^1] == args.Step, }; - RaiseLocalEvent(step, ref ev); + RaiseLocalEvent(step, ref evComplete); if (_net.IsClient) return; _delayAccumulator = 0f; _delayQueue.Enqueue(() => RefreshUI(ent)); } - private void OnClearProgressStep(Entity ent, ref SurgeryStepEvent args) + private void OnClearProgressStep(Entity ent, ref SurgeryStepCompleteEvent args) { var progress = Comp(args.Part); progress.CompletedSteps.Clear(); progress.CompletedSurgeries.Clear(); } - + private void OnStepComplete(Entity ent, ref SurgeryStepCompleteEvent args) + { + if (TryComp(ent, out _)) return; + if (TryComp(args.Part, out var progress)) + { + progress.CompletedSteps.Add($"{args.SurgeryProto}:{args.StepProto}"); + if (!progress.StartedSurgeries.Contains(args.SurgeryProto) && !args.IsFinal) + progress.StartedSurgeries.Add(args.SurgeryProto); + if (progress.StartedSurgeries.Contains(args.SurgeryProto) && args.IsFinal) + progress.StartedSurgeries.Remove(args.SurgeryProto); + } + else + { + progress = new SurgeryProgressComponent { CompletedSteps = [$"{args.SurgeryProto}:{args.StepProto}"]}; + if(!args.IsFinal) + progress.StartedSurgeries.Add(args.SurgeryProto); + AddComp(args.Part, progress); + } + if (args.IsFinal) + progress.CompletedSurgeries.Add(args.SurgeryProto); + } private void OnStep(Entity ent, ref SurgeryStepEvent args) { - if (!TryComp(ent, out _)) - { - if (TryComp(args.Part, out var progress)) - { - progress.CompletedSteps.Add($"{args.SurgeryProto}:{args.StepProto}"); - if(!progress.StartedSurgeries.Contains(args.SurgeryProto) && !args.IsFinal) - progress.StartedSurgeries.Add(args.SurgeryProto); - if (progress.StartedSurgeries.Contains(args.SurgeryProto) && args.IsFinal) - progress.StartedSurgeries.Remove(args.SurgeryProto); - } - else - { - progress = new SurgeryProgressComponent { CompletedSteps = [$"{args.SurgeryProto}:{args.StepProto}"] }; - AddComp(args.Part, progress); - } - if (args.IsFinal) - progress.CompletedSurgeries.Add(args.SurgeryProto); - } - foreach (var reg in (ent.Comp.Tools ?? []).Values) { var tool = args.Tools.FirstOrDefault(x => HasComp(x, reg.Component.GetType())); @@ -130,6 +151,28 @@ public abstract partial class SharedSurgerySystem RaiseLocalEvent(args.Body, ref args); + if (args.Invalid != StepInvalidReason.None) + return; + + if (_inventory.TryGetContainerSlotEnumerator(args.Body, out var enumerator, args.TargetSlots)) + { + var items = 0f; + var total = 0f; + while (enumerator.MoveNext(out var con)) + { + total++; + if (con.ContainedEntity != null) + items++; + } + + if (items > 0) + { + args.Invalid = StepInvalidReason.Armor; + args.Popup = Loc.GetString("surgery-need-remove-armor"); + return; + } + } + if (args.Invalid != StepInvalidReason.None || ent.Comp.Tools == null) return; @@ -141,10 +184,24 @@ public abstract partial class SharedSurgerySystem args.Invalid = StepInvalidReason.MissingTool; if (reg.Component is ISurgeryToolComponent toolComp) - args.Popup = $"You need {toolComp.ToolName} to perform this step!"; + args.Popup = Loc.GetString("surgery-need-tool"); return; } + else if (TryComp(tool, out var togglable) && !togglable.Activated) + { + args.Invalid = StepInvalidReason.DisabledTool; + + if (reg.Component is ISurgeryToolComponent toolComp) + args.Popup = Loc.GetString("surgery-need-enable"); + + return; + } + else if (TryComp(ent, out var itemSizeComp) && TryComp(tool, out var item) && _item.GetSizePrototype(item.Size) > _item.GetSizePrototype(itemSizeComp.Size)) + { + args.Invalid = StepInvalidReason.TooHigh; + return; + } args.ValidTools.Add(tool); } @@ -162,7 +219,7 @@ public abstract partial class SharedSurgerySystem { return; } - if(!PreviousStepsComplete(body, part, surgery, args.Step) || IsStepComplete(part, args.Surgery, args.Step)) + if (!PreviousStepsComplete(body, part, surgery, args.Step) || IsStepComplete(part, args.Surgery, args.Step)) { var progress = Comp(part); Dirty(part, progress); @@ -173,17 +230,22 @@ public abstract partial class SharedSurgerySystem var duration = stepComp.Duration; + float SmallestSuccessRate = 1f; + foreach (var tool in validTools) if (TryComp(tool, out SurgeryToolComponent? toolComp)) { duration *= toolComp.Speed; if (toolComp.StartSound != null) _audio.PlayPvs(toolComp.StartSound, tool); + + if(toolComp.SuccessRate < SmallestSuccessRate) + SmallestSuccessRate = toolComp.SuccessRate; } if (TryComp(body, out TransformComponent? xform)) _rotateToFace.TryFaceCoordinates(user, _transform.GetMapCoordinates(body, xform).Position); - var ev = new SurgeryDoAfterEvent(args.Surgery, args.Step); + var ev = new SurgeryDoAfterEvent(args.Surgery, args.Step, SmallestSuccessRate); var doAfter = new DoAfterArgs(EntityManager, user, duration, ev, body, part) { BreakOnMove = true, @@ -204,10 +266,16 @@ public abstract partial class SharedSurgerySystem requirements.Add(surgery); - if (surgery.Comp.Requirement is { } requirementId && - GetSingleton(requirementId) is { } requirement && - GetNextStep(body, part, requirement, requirements) is { } requiredNext) - return requiredNext; + if (surgery.Comp.Requirement is { } requirementsIds) + { + foreach (var requirementId in requirementsIds) + { + if (GetSingleton(requirementId) is { } requirement + && GetNextStep(body, part, requirement, requirements) is { } requiredNext + && IsSurgeryValid(body, part, requirementId, requiredNext.Surgery.Comp.Steps[requiredNext.Step], out _, out _, out _)) + return requiredNext; + } + } if (!TryComp(part, out var progress)) { @@ -224,13 +292,15 @@ public abstract partial class SharedSurgerySystem public bool PreviousStepsComplete(EntityUid body, EntityUid part, Entity surgery, EntProtoId step) { - if (surgery.Comp.Requirement is { } requirement) + if (surgery.Comp.Requirement is { } requirements) { - if (GetSingleton(requirement) is not { } requiredEnt || - !TryComp(requiredEnt, out SurgeryComponent? requiredComp) || - !PreviousStepsComplete(body, part, (requiredEnt, requiredComp), step)) + foreach (var requirement in requirements) { - return false; + if (GetSingleton(requirement) is not { } requiredEnt + || !TryComp(requiredEnt, out SurgeryComponent? requiredComp) + || !PreviousStepsComplete(body, part, (requiredEnt, requiredComp), step) + && IsSurgeryValid(body, part, requirement, step, out _, out _, out _)) + return false; } } @@ -251,7 +321,7 @@ public abstract partial class SharedSurgerySystem { var slot = part switch { - BodyPartType.Head => SlotFlags.HEAD, + BodyPartType.Head => SlotFlags.HEAD | SlotFlags.MASK | SlotFlags.EYES, BodyPartType.Torso => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, BodyPartType.Arm => SlotFlags.OUTERCLOTHING | SlotFlags.INNERCLOTHING, BodyPartType.Hand => SlotFlags.GLOVES, diff --git a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.Conditions.cs b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.Conditions.cs index ae2361b2fa..cdb3bcc1e1 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.Conditions.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.Conditions.cs @@ -1,8 +1,11 @@ using Content.Shared.Body.Part; +using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Humanoid; using System.Linq; using Content.Shared._Sunrise.Medical.Surgery.Steps.Parts; using Content.Shared._Sunrise.Medical.Surgery.Events; using Content.Shared._Sunrise.Medical.Surgery.Effects.Step; +using Content.Shared.Body.Systems; namespace Content.Shared._Sunrise.Medical.Surgery; // Based on the RMC14. @@ -17,33 +20,86 @@ public abstract partial class SharedSurgerySystem .ToList(); SubscribeLocalEvent(OnPartConditionValid); + SubscribeLocalEvent(OnSpeciesConditionValid); SubscribeLocalEvent(OnOrganExistConditionValid); SubscribeLocalEvent(OnOrganDontExistConditionValid); SubscribeLocalEvent(OnAnyAccentConditionValid); SubscribeLocalEvent(OnAnyLimbSlotConditionValid); + SubscribeLocalEvent(OnLimbSlotConditionValid); } + private void OnOrganDontExistConditionValid(Entity ent, ref SurgeryValidEvent args) { if (ent.Comp.Organ?.Count != 1) return; var type = ent.Comp.Organ.Values.First().Component.GetType(); - var organs = _body.GetPartOrgans(args.Part, Comp(args.Part)); - foreach (var organ in organs) - if (HasComp(organ.Id, type)) + if (ent.Comp.Container != null) + { + foreach (var slotId in Comp(args.Part).Organs.Keys) { - args.Cancelled = true; - return; + if (ent.Comp.Container == slotId) + { + if (!_containers.TryGetContainer(args.Part, ent.Comp.Container, out var container)) + continue; + + foreach (var containedEnt in container.ContainedEntities) + { + if (HasComp(containedEnt, type)) + { + args.Cancelled = true; + return; + } + } + } } + } + else + { + var organs = _body.GetPartOrgans(args.Part, Comp(args.Part)); + foreach (var organ in organs) + if (HasComp(organ.Id, type)) + { + args.Cancelled = true; + return; + } + } } private void OnOrganExistConditionValid(Entity ent, ref SurgeryValidEvent args) { if (ent.Comp.Organ?.Count != 1) return; - var organs = _body.GetPartOrgans(args.Part, Comp(args.Part)); + var type = ent.Comp.Organ.Values.First().Component.GetType(); - foreach (var organ in organs) - if (HasComp(organ.Id, type)) - return; - args.Cancelled = true; + + EntityUid mainPart = args.Part; + + if (TryComp(args.Body, out var itemPart)) + mainPart = args.Body; + + if (ent.Comp.Container != null) + { + foreach (var slotId in Comp(mainPart).Organs.Keys) + { + if (ent.Comp.Container == slotId) + { + if (!_containers.TryGetContainer(mainPart, SharedBodySystem.GetOrganContainerId(ent.Comp.Container), out var container)) + continue; + + foreach (var containedEnt in container.ContainedEntities) + if (HasComp(containedEnt, type)) + return; + + args.Cancelled = true; + } + } + } + else + { + var organs = _body.GetPartOrgans(mainPart, Comp(mainPart)); + foreach (var organ in organs) + if (HasComp(organ.Id, type)) + return; + args.Cancelled = true; + } } private void OnPartConditionValid(Entity ent, ref SurgeryValidEvent args) @@ -51,9 +107,35 @@ public abstract partial class SharedSurgerySystem if (ent.Comp.Parts.Count == 0) return; + if (TryComp(args.Body, out var itemPart) && itemPart.PartType is BodyPartType item && !ent.Comp.Parts.Contains(item)) + { + Logger.Warning("don't have part at part"); + args.Cancelled = true; + } + if (CompOrNull(args.Part)?.PartType is BodyPartType part && !ent.Comp.Parts.Contains(part)) args.Cancelled = true; } + private void OnSpeciesConditionValid(Entity ent, ref SurgeryValidEvent args) + { + if (!EntityManager.TryGetComponent(args.Body, out var humanoidAppearanceComponent)) + { + args.Cancelled = true; + return; + } + + if (ent.Comp.SpeciesBlacklist.Contains(humanoidAppearanceComponent.Species)) + { + args.Cancelled = true; + return; + } + + if (ent.Comp.SpeciesWhitelist.Count > 0 && !ent.Comp.SpeciesWhitelist.Contains(humanoidAppearanceComponent.Species)) + { + args.Cancelled = true; + return; + } + } private void OnAnyAccentConditionValid(Entity ent, ref SurgeryValidEvent args) { foreach (var accent in _accents) @@ -71,4 +153,7 @@ public abstract partial class SharedSurgerySystem else args.Cancelled = true; } + private void OnLimbSlotConditionValid(Entity ent, ref SurgeryValidEvent args) + => args.Cancelled = !(_containers.TryGetContainer(args.Part, SharedBodySystem.GetPartSlotContainerId(ent.Comp.Slot), out var container) + && container.ContainedEntities.Count == 0); } diff --git a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.cs b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.cs index d94ce70814..b24b6324da 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/SharedSurgerySystem.cs @@ -12,6 +12,8 @@ using Content.Shared.DoAfter; using Content.Shared.GameTicking; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.Popups; using Content.Shared.Standing; using Robust.Shared.Audio.Systems; @@ -43,6 +45,8 @@ public abstract partial class SharedSurgerySystem : EntitySystem [Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly SharedContainerSystem _containers = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedItemSystem _item = default!; private readonly Dictionary _surgeries = new(); @@ -61,7 +65,7 @@ public abstract partial class SharedSurgerySystem : EntitySystem _surgeries.Clear(); } - protected bool IsSurgeryValid(EntityUid body, EntityUid targetPart, EntProtoId surgery, EntProtoId stepId, out Entity surgeryEnt, out Entity part, out EntityUid step) + public bool IsSurgeryValid(EntityUid body, EntityUid targetPart, EntProtoId surgery, EntProtoId stepId, out Entity surgeryEnt, out Entity part, out EntityUid step) { surgeryEnt = default; part = default; @@ -125,6 +129,9 @@ public abstract partial class SharedSurgerySystem : EntitySystem if (_standing.IsDown(entity)) return true; + if (HasComp(entity)) + return true; + if (TryComp(entity, out BuckleComponent? buckle) && TryComp(buckle.BuckledTo, out StrapComponent? strap)) { diff --git a/Content.Shared/_Sunrise/Medical/Surgery/StepInvalidReason.cs b/Content.Shared/_Sunrise/Medical/Surgery/StepInvalidReason.cs index 7610102ca7..f2c65291ea 100644 --- a/Content.Shared/_Sunrise/Medical/Surgery/StepInvalidReason.cs +++ b/Content.Shared/_Sunrise/Medical/Surgery/StepInvalidReason.cs @@ -7,4 +7,6 @@ public enum StepInvalidReason NeedsOperatingTable, Armor, MissingTool, + DisabledTool, + TooHigh, } diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/surgery/steps.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/steps.ftl new file mode 100644 index 0000000000..1e9797c374 --- /dev/null +++ b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/steps.ftl @@ -0,0 +1,4 @@ +surgery-careless-tool = Из-за небрежного обращения с инструментом ваша рука дрогнула. Вам придется начать этот шаг заново! +surgery-need-remove-armor = Чтобы выполнить этот шаг, необходимо снять броню с пациента! +surgery-need-tool = Вам необходим {toolComp.ToolName} чтобы выполнить этот шаг! +surgery-need-enable = Вам необходимо включить {toolComp.ToolName} чтобы выполнить шаг! diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/surgery/surgery.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/surgery.ftl new file mode 100644 index 0000000000..e554af57c2 --- /dev/null +++ b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/surgery.ftl @@ -0,0 +1 @@ +cant-perform-operation-on-yourself = Вы не можете провести операцию на самом себе! diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/surgery/window.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/window.ftl index 9ffe1abab5..07f5a7f403 100644 --- a/Resources/Locale/ru-RU/_strings/_sunrise/surgery/window.ftl +++ b/Resources/Locale/ru-RU/_strings/_sunrise/surgery/window.ftl @@ -1,9 +1,11 @@ surgery-window-name = Хирургия -surgery-window-partsbutton-name = Части тела -surgery-window-surgeriesbutton-name = Операции -surgery-window-stepsbutton-name = Этапы +surgery-window-partsbutton-name = < Части тела +surgery-window-surgeriesbutton-name = < Операции +surgery-window-stepsbutton-name = < Этапы surgery-window-reguires = [bold]Требует: { $surgeryname }[/bold] surgery-window-reguires-table = [color=red](Требует операционный стол)[/color] surgery-window-reguires-undress = [color=red](Снимите с него броню!)[/color] surgery-window-reguires-tool = [color=red](Отсутствует инструмент)[/color] surgery-window-reguires-laydown = [color=red][font size=16]Он должен лежать![/font][/color] +surgery-window-reguires-enable = [color=red](Предмет выключен)[/color] +surgery-window-too-high = [color=red](Слишком высокий)[/color] diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index e59aad9da3..0a8675e3ca 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -128,7 +128,7 @@ - type: entity id: OrganAnimalHeart - parent: BaseAnimalOrgan + parent: [ BaseAnimalOrgan, BaseOrganHeart] name: heart categories: [ HideSpawnMenu ] components: diff --git a/Resources/Prototypes/Body/Organs/arachnid.yml b/Resources/Prototypes/Body/Organs/arachnid.yml index 0cd10a8780..5f590f2821 100644 --- a/Resources/Prototypes/Body/Organs/arachnid.yml +++ b/Resources/Prototypes/Body/Organs/arachnid.yml @@ -160,6 +160,9 @@ - type: Item size: Small heldPrefix: eyeballs + - type: OrganVisualization + layer: Eyes + prototype: MobArachnidEyes - type: entity id: OrganArachnidTongue diff --git a/Resources/Prototypes/Body/Organs/base.yml b/Resources/Prototypes/Body/Organs/base.yml index 6b2ca58509..0149cbeddd 100644 --- a/Resources/Prototypes/Body/Organs/base.yml +++ b/Resources/Prototypes/Body/Organs/base.yml @@ -19,7 +19,10 @@ Caustic: 5 - type: Damageable damageContainer: Biological - + - type: OrganVisualization + layer: Eyes + prototype: MobHumanoidEyes + - type: entity id: BaseOrganTongue abstract: true diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml index 69167030e5..035068df6d 100644 --- a/Resources/Prototypes/Body/Organs/diona.yml +++ b/Resources/Prototypes/Body/Organs/diona.yml @@ -62,6 +62,9 @@ layers: - state: eyeball-l - state: eyeball-r + - type: OrganVisualization + layer: Eyes + prototype: MobDionaEyes - type: entity id: OrganDionaStomach diff --git a/Resources/Prototypes/Body/Organs/human.yml b/Resources/Prototypes/Body/Organs/human.yml index 24666a22fb..096c7a481d 100644 --- a/Resources/Prototypes/Body/Organs/human.yml +++ b/Resources/Prototypes/Body/Organs/human.yml @@ -88,6 +88,9 @@ - type: Item size: Small heldPrefix: eyeballs + - type: OrganVisualization + layer: Eyes + prototype: MobHumanoidEyes - type: entity id: OrganHumanTongue diff --git a/Resources/Prototypes/Body/Organs/slime.yml b/Resources/Prototypes/Body/Organs/slime.yml index e498d45f7f..150dc64af7 100644 --- a/Resources/Prototypes/Body/Organs/slime.yml +++ b/Resources/Prototypes/Body/Organs/slime.yml @@ -15,9 +15,11 @@ groups: - id: Food - id: Drink - - id: Medicine - - id: Poison - - id: Narcotic + # Sunrise-start + #- id: Medicine + #- id: Poison + #- id: Narcotic + # Sunrise-end - id: Alcohol rateModifier: 0.25 - type: SolutionContainerManager @@ -37,7 +39,6 @@ size: Small heldPrefix: brain - - type: entity id: OrganSlimeLungs parent: [BaseHumanOrgan, BaseOrganLungs] diff --git a/Resources/Prototypes/Body/Parts/base.yml b/Resources/Prototypes/Body/Parts/base.yml index f9ced56644..607fcfb80d 100644 --- a/Resources/Prototypes/Body/Parts/base.yml +++ b/Resources/Prototypes/Body/Parts/base.yml @@ -20,6 +20,13 @@ - type: Tag tags: - Trash + # Sunrise-start + - type: SurgeryTarget + - type: UserInterface + interfaces: + enum.SurgeryUIKey.Key: + type: SurgeryBui + # Sunrise-end - type: entity id: BaseTorso diff --git a/Resources/Prototypes/Body/Prototypes/arachnid.yml b/Resources/Prototypes/Body/Prototypes/arachnid.yml index 044d9d3975..f4689c7c92 100644 --- a/Resources/Prototypes/Body/Prototypes/arachnid.yml +++ b/Resources/Prototypes/Body/Prototypes/arachnid.yml @@ -10,20 +10,31 @@ organs: brain: OrganHumanBrain eyes: OrganArachnidEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoArachnid + # Sunrise-start + connections: + - right arm + - left arm + - right leg + - left leg + # Sunrise-end organs: heart: OrganArachnidHeart lungs: OrganAnimalLungs stomach: OrganArachnidStomach liver: OrganArachnidLiver kidneys: OrganArachnidKidneys - connections: - - right arm - - left arm - - right leg - - left leg + cavity: null # Sunrise-edit + # connections: + # - right arm + # - left arm + # - right leg + # - left leg right arm: part: RightArmArachnid connections: diff --git a/Resources/Prototypes/Body/Prototypes/diona.yml b/Resources/Prototypes/Body/Prototypes/diona.yml index cf913f8393..4e1d0c490c 100644 --- a/Resources/Prototypes/Body/Prototypes/diona.yml +++ b/Resources/Prototypes/Body/Prototypes/diona.yml @@ -21,6 +21,8 @@ organs: stomach: OrganDionaStomachNymph lungs: OrganDionaLungsNymph + heart: null # Sunrise-edit + cavity: null # Sunrise-edit right arm: part: RightArmDiona connections: diff --git a/Resources/Prototypes/Body/Prototypes/dwarf.yml b/Resources/Prototypes/Body/Prototypes/dwarf.yml index 5c02b73e50..e83e198f19 100644 --- a/Resources/Prototypes/Body/Prototypes/dwarf.yml +++ b/Resources/Prototypes/Body/Prototypes/dwarf.yml @@ -10,20 +10,31 @@ organs: brain: OrganHumanBrain eyes: OrganHumanEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoHuman + # Sunrise-start connections: - right arm - left arm - right leg - left leg + # Sunrise-end organs: heart: OrganDwarfHeart lungs: OrganHumanLungs stomach: OrganDwarfStomach liver: OrganDwarfLiver kidneys: OrganHumanKidneys + cavity: null # Sunrise-edit + # connections: + # - right arm + # - left arm + # - right leg + # - left leg right arm: part: RightArmHuman connections: diff --git a/Resources/Prototypes/Body/Prototypes/gingerbread.yml b/Resources/Prototypes/Body/Prototypes/gingerbread.yml index 31e78e276d..8a1eb64316 100644 --- a/Resources/Prototypes/Body/Prototypes/gingerbread.yml +++ b/Resources/Prototypes/Body/Prototypes/gingerbread.yml @@ -24,6 +24,7 @@ stomach: OrganHumanStomach liver: OrganHumanLiver kidneys: OrganHumanKidneys + cavity: null # Sunrise-edit right arm: part: RightArmGingerbread connections: diff --git a/Resources/Prototypes/Body/Prototypes/human.yml b/Resources/Prototypes/Body/Prototypes/human.yml index 3bac4ccf35..50f389843b 100644 --- a/Resources/Prototypes/Body/Prototypes/human.yml +++ b/Resources/Prototypes/Body/Prototypes/human.yml @@ -10,41 +10,43 @@ organs: brain: OrganHumanBrain eyes: OrganHumanEyes - tongue: OrganHumanTongue + tongue: OrganHumanTongue # Sunrise-edit torso: part: TorsoHuman connections: - - right_arm - - left_arm - - right_leg - - left_leg + - right arm # STARLIGHT-SURGERY EDITED, be careful to not delete this + - left arm + - right leg + - left leg organs: heart: OrganHumanHeart lungs: OrganHumanLungs stomach: OrganHumanStomach liver: OrganHumanLiver kidneys: OrganHumanKidneys - right_arm: + cavity: null # Sunrise-edit + right arm: part: RightArmHuman connections: - - right_hand - left_arm: + - right hand + left arm: part: LeftArmHuman connections: - - left_hand - right_hand: + - left hand + right hand: part: RightHandHuman - left_hand: + left hand: part: LeftHandHuman - right_leg: + right leg: part: RightLegHuman connections: - - right_foot - left_leg: + - right foot + left leg: part: LeftLegHuman connections: - - left_foot - right_foot: + - left foot + right foot: part: RightFootHuman - left_foot: + left foot: part: LeftFootHuman + diff --git a/Resources/Prototypes/Body/Prototypes/moth.yml b/Resources/Prototypes/Body/Prototypes/moth.yml index 882d65ae47..73453fe647 100644 --- a/Resources/Prototypes/Body/Prototypes/moth.yml +++ b/Resources/Prototypes/Body/Prototypes/moth.yml @@ -10,20 +10,31 @@ organs: brain: OrganHumanBrain eyes: OrganHumanEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoMoth + # Sunrise-start + connections: + - right arm + - left arm + - right leg + - left leg + # Sunrise-end organs: heart: OrganAnimalHeart lungs: OrganHumanLungs stomach: OrganMothStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys - connections: - - right arm - - left arm - - right leg - - left leg + cavity: null # Sunrise-edit + # connections: + # - right arm + # - left arm + # - right leg + # - left leg right arm: part: RightArmMoth connections: diff --git a/Resources/Prototypes/Body/Prototypes/primate.yml b/Resources/Prototypes/Body/Prototypes/primate.yml index d8e09d9a81..1d84f9e050 100644 --- a/Resources/Prototypes/Body/Prototypes/primate.yml +++ b/Resources/Prototypes/Body/Prototypes/primate.yml @@ -14,6 +14,7 @@ liver: OrganAnimalLiver heart: OrganPrimateHeart # Sunrise Edit kidneys: OrganAnimalKidneys + cavity: null # Sunrise-edit hands: part: HandsAnimal legs: diff --git a/Resources/Prototypes/Body/Prototypes/rat.yml b/Resources/Prototypes/Body/Prototypes/rat.yml index fe77288994..0fb37c84ee 100644 --- a/Resources/Prototypes/Body/Prototypes/rat.yml +++ b/Resources/Prototypes/Body/Prototypes/rat.yml @@ -13,6 +13,7 @@ liver: OrganAnimalLiver heart: OrganAnimalHeart kidneys: OrganAnimalKidneys + cavity: null # Sunrise-edit legs: part: LegsAnimal connections: diff --git a/Resources/Prototypes/Body/Prototypes/reptilian.yml b/Resources/Prototypes/Body/Prototypes/reptilian.yml index b56c2a1f42..2cd8468e5b 100644 --- a/Resources/Prototypes/Body/Prototypes/reptilian.yml +++ b/Resources/Prototypes/Body/Prototypes/reptilian.yml @@ -10,20 +10,31 @@ organs: brain: OrganHumanBrain eyes: OrganHumanEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoReptilian + # Sunrise-start + connections: + - right arm + - left arm + - right leg + - left leg + # Sunrise-end organs: heart: OrganAnimalHeart lungs: OrganHumanLungs stomach: OrganReptilianStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys - connections: - - right arm - - left arm - - right leg - - left leg + cavity: null # Sunrise-edit + # connections: + # - right arm + # - left arm + # - right leg + # - left leg right arm: part: RightArmReptilian connections: diff --git a/Resources/Prototypes/Body/Prototypes/slime.yml b/Resources/Prototypes/Body/Prototypes/slime.yml index a1ee5d9f34..b5e80d84e1 100644 --- a/Resources/Prototypes/Body/Prototypes/slime.yml +++ b/Resources/Prototypes/Body/Prototypes/slime.yml @@ -9,7 +9,10 @@ - torso organs: eyes: OrganHumanEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoSlime connections: @@ -18,8 +21,10 @@ - right leg - left leg organs: + heart: OrganSlimeHeart # Sunrise-edit core: SentientSlimeCore lungs: OrganSlimeLungs + cavity: null # Sunrise-edit right arm: part: RightArmSlime connections: diff --git a/Resources/Prototypes/Body/Prototypes/terminator.yml b/Resources/Prototypes/Body/Prototypes/terminator.yml index c271a89d86..581a7a47b7 100644 --- a/Resources/Prototypes/Body/Prototypes/terminator.yml +++ b/Resources/Prototypes/Body/Prototypes/terminator.yml @@ -10,6 +10,7 @@ - torso organs: brain: MobTerminatorEndoskeleton + cavity: null # Sunrise-edit torso: part: TorsoHuman connections: diff --git a/Resources/Prototypes/Body/Prototypes/vox.yml b/Resources/Prototypes/Body/Prototypes/vox.yml index 96ac49a25b..d9b7590ac2 100644 --- a/Resources/Prototypes/Body/Prototypes/vox.yml +++ b/Resources/Prototypes/Body/Prototypes/vox.yml @@ -10,7 +10,10 @@ organs: brain: OrganHumanBrain eyes: OrganHumanEyes + # Sunrise-start tongue: OrganHumanTongue + eye_implant: null + # Sunrise-end torso: part: TorsoVox connections: @@ -24,6 +27,7 @@ stomach: OrganVoxStomach liver: OrganVoxLiver kidneys: OrganHumanKidneys + cavity: null # Sunrise-edit right arm: part: RightArmVox connections: diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index 13160aa328..c71a0a5903 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -4,7 +4,6 @@ id: BaseMobSlimePerson abstract: true components: - - type: Absorbable - type: Hunger - type: Thirst baseDecayRate: 0.3 @@ -40,7 +39,13 @@ type: StrippableBoundUserInterface enum.StoreUiKey.Key: type: StoreBoundUserInterface - # to prevent bag open/honk spam + # Sunrise-start + enum.SurgeryUIKey.Key: + type: SurgeryBui + enum.VampireMutationUiKey.Key: + type: VampireMutationBoundUserInterface + - type: Absorbable + # Sunrise-end - type: UseDelay delay: 0.5 - type: HumanoidAppearance diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index 59669ac2b2..852f6b09b1 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -48,7 +48,50 @@ - type: TTS - type: DamageOverlay - type: EmoteAnimation - # Sunrise-End + - type: CustomLimbVisualizer + displacements: + LHand: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: l_hand + RHand: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: r_hand + LLeg: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: l_leg + RLeg: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: r_leg + LFoot: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: l_foot + RFoot: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: r_foot + LArm: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: l_arm + RArm: + sizeMaps: + 32: + sprite: _Sunrise/CustomLimb/displacement.rsi + state: r_arm + # Sunrise-end + - type: entity save: false diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index 2457404b48..b5a1c0963b 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -79,6 +79,15 @@ - type: DeleteOnTrigger - type: StaticPrice price: 0 + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity parent: ShardBase diff --git a/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml b/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml index 5484f78cc2..16d2e2f0bd 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml @@ -24,6 +24,15 @@ Piercing: 6 soundHit: path: "/Audio/Weapons/bladeslice.ogg" + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.12 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: PhysicalComposition materialComposition: Steel: 200 diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index 4d7365508f..3cad212969 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -4,6 +4,15 @@ id: Lighter description: "A simple plastic cigarette lighter." components: + # Sunrise-start + - type: SurgeryTool + successRate: 0.1 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/cautery1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/cautery2.ogg + - type: Cautery + # Sunrise-end - type: IgnitionSource ignited: false - type: ItemToggle diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 8b7e9d9ddd..5d78a3266d 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -55,6 +55,15 @@ Steel: 100 - type: StaticPrice price: 30 + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.35 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity name: screwdriver diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml index bfdd94add6..dfb721c353 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml @@ -47,3 +47,12 @@ maxVol: 300 - type: UseDelay delay: 1 + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.01 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 833096fbbd..d4ebe0b421 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -98,6 +98,15 @@ sprite: Objects/Weapons/Melee/e_sword-inhands.rsi - type: StaticPrice price: 2500 + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity name: energy dagger @@ -162,6 +171,15 @@ energy: 1.5 color: white netsync: false + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity name: pen @@ -232,6 +250,15 @@ tags: - Write - NoPaint # Sunrise-edit + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity parent: [BaseItem, BaseSyndicateContraband] @@ -341,6 +368,15 @@ spread: 75 - type: FlipOnAttack # Sunrise-Edit probability: 0.5 # Sunrise-Edit + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end # Item will look weird in handslot. Will need to adjust handstorage visuals in a future PR - type: entity @@ -413,3 +449,12 @@ - type: EnergySword colorOptions: - "#2288ff" # can only be blue + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 993c7eb6ce..80a1c284be 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -27,6 +27,15 @@ - Slicing useSound: path: /Audio/Items/Culinary/chop.ogg + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.9 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity name: kitchen knife @@ -210,6 +219,15 @@ sprite: Objects/Weapons/Melee/shiv.rsi - type: DisarmMalus malus: 0.225 + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.7 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end - type: entity name: reinforced shiv diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index d4b52c6a71..3307292e26 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -209,8 +209,17 @@ - Back - SuitStorage #Bigger than the other swords, easier to strap to your suit. - type: DisarmMalus + # Sunrise-start + - type: Scalpel + - type: SurgeryTool + successRate: 0.6 + startSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/_Sunrise/Medical/Surgery/scalpel2.ogg + # Sunrise-end + -#Other/Weird - type: entity name: throngler parent: [ BaseSword, BaseMajorContraband ] diff --git a/Resources/Prototypes/_Sunrise/Body/Organs/slime.yml b/Resources/Prototypes/_Sunrise/Body/Organs/slime.yml new file mode 100644 index 0000000000..8314d6618c --- /dev/null +++ b/Resources/Prototypes/_Sunrise/Body/Organs/slime.yml @@ -0,0 +1,20 @@ +- type: entity + id: OrganSlimeHeart + parent: [BaseHumanOrgan, BaseOrganHeart] + name: slime circulator + description: "A little circulator what makes the fluid move through the slime body." + components: + - type: Sprite + sprite: _Sunrise/Mobs/Species/Slime/organs.rsi + state: heart-on + - type: Item + size: Small + heldPrefix: heart + - type: Metabolizer + maxReagents: 6 + metabolizerTypes: [ Slime ] + removeEmpty: true + groups: + - id: Medicine + - id: Poison + - id: Narcotic diff --git a/Resources/Prototypes/_Sunrise/Body/Parts/virtual.yml b/Resources/Prototypes/_Sunrise/Body/Parts/virtual.yml new file mode 100644 index 0000000000..68092cbab8 --- /dev/null +++ b/Resources/Prototypes/_Sunrise/Body/Parts/virtual.yml @@ -0,0 +1,5 @@ +- type: entity + id: PartVirtual + parent: BaseItem + components: + - type: BodyPart \ No newline at end of file diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/animal.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/animal.yml index f0b2ee5a46..20e2db6a9c 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/animal.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/animal.yml @@ -13,6 +13,7 @@ liver: OrganAnimalLiver heart: OrganPigHeart kidneys: OrganAnimalKidneys + cavity: null legs: part: LegsAnimal connections: @@ -90,4 +91,4 @@ connections: - feet feet: - part: FeetAnimal \ No newline at end of file + part: FeetAnimal diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/clowns.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/clowns.yml index 223f2a9e37..362c0ba8f7 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/clowns.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/clowns.yml @@ -14,6 +14,7 @@ liver: OrganBloodsuckerLiver heart: OrganBloodsuckerHeart kidneys: OrganAnimalKidneys + cavity: null right arm: part: RightArmHuman connections: @@ -25,4 +26,4 @@ right hand: part: RightHandHuman left hand: - part: LeftHandHuman \ No newline at end of file + part: LeftHandHuman diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/demon.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/demon.yml index cdacb3a561..020142724b 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/demon.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/demon.yml @@ -18,6 +18,7 @@ stomach: OrganDemonStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys + cavity: null connections: - right arm - left arm @@ -46,4 +47,4 @@ right foot: part: RightFootDemon left foot: - part: LeftFootDemon \ No newline at end of file + part: LeftFootDemon diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/felinid.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/felinid.yml index 53876e4988..26f51b1580 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/felinid.yml @@ -14,7 +14,7 @@ part: TorsoHuman connections: - right arm - - left arm + - left arm - left leg - right leg organs: @@ -23,6 +23,7 @@ stomach: OrganReptilianStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys + cavity: null right arm: part: RightArmHuman connections: diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/humanoid_xeno.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/humanoid_xeno.yml index 6689071f04..639c20d5da 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/humanoid_xeno.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/humanoid_xeno.yml @@ -19,6 +19,7 @@ stomach: OrganHumanoidXenoStomach liver: OrganHumanoidXenoLiver kidneys: OrganHumanoidXenoKidneys + cavity: null connections: - right arm - left arm diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/predator.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/predator.yml index 2363adcca9..f6ae06fa34 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/predator.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/predator.yml @@ -19,6 +19,7 @@ stomach: OrganPredatorStomach liver: OrganPredatorLiver kidneys: OrganPredatorKidneys + cavity: null connections: - right arm - left arm diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/swine.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/swine.yml index 935d13f54b..7982dd082a 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/swine.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/swine.yml @@ -18,6 +18,7 @@ stomach: OrganSwineStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys + cavity: null connections: - right arm - left arm diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/tajaran.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/tajaran.yml index bf1fce7184..2a594eebe8 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/tajaran.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/tajaran.yml @@ -18,6 +18,7 @@ stomach: OrganTajaranStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys + cavity: null connections: - right arm - left arm diff --git a/Resources/Prototypes/_Sunrise/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/_Sunrise/Body/Prototypes/vulpkanin.yml index 03e9cda764..2340fc4412 100644 --- a/Resources/Prototypes/_Sunrise/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/_Sunrise/Body/Prototypes/vulpkanin.yml @@ -18,6 +18,7 @@ stomach: OrganVulpkaninStomach liver: OrganAnimalLiver kidneys: OrganHumanKidneys + cavity: null connections: - right_arm - left_arm diff --git a/Resources/Prototypes/_Sunrise/Surgery/amputation_steps.yml b/Resources/Prototypes/_Sunrise/Surgery/amputation_steps.yml index dd608cf4b5..a2ca8e580b 100644 --- a/Resources/Prototypes/_Sunrise/Surgery/amputation_steps.yml +++ b/Resources/Prototypes/_Sunrise/Surgery/amputation_steps.yml @@ -16,3 +16,70 @@ types: Slash: 24 - type: SurgeryStepAmputationEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepExposeSkull + name: Expose Skull + components: + - type: SurgeryStep + duration: 2 + tools: + - type: BoneSaw + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/saw.rsi + state: saw + - type: SurgeryStepBleedEffect + damage: + types: + Slash: 5 + - type: SurgeryStepEmoteEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepLigateVessels + name: Ligate Vessels + components: + - type: SurgeryStep + duration: 3 + tools: + - type: Hemostat + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scissors.rsi + state: hemostat + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepSawSkull + name: Saw Skull + components: + - type: SurgeryStep + duration: 20 + tools: + - type: BoneSaw + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/saw.rsi + state: saw + - type: SurgeryStepBleedEffect + damage: + types: + Slash: 15 + - type: SurgeryStepAmputationEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepInciseCartilage + name: Incise Cartilage + components: + - type: SurgeryStep + tools: + - type: Scalpel + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scalpel.rsi + state: scalpel + + +- type: entity + parent: SurgeryStepSawSkull + id: SurgeryStepHeadFinalizeSeparation + name: Finalize Separation \ No newline at end of file diff --git a/Resources/Prototypes/_Sunrise/Surgery/amputation_surgeries.yml b/Resources/Prototypes/_Sunrise/Surgery/amputation_surgeries.yml new file mode 100644 index 0000000000..31dc7cfd8e --- /dev/null +++ b/Resources/Prototypes/_Sunrise/Surgery/amputation_surgeries.yml @@ -0,0 +1,78 @@ +- type: entity + parent: SurgeryBase + id: SurgeryAmputation + name: Amputation + description: Surgical removal of a limb. + components: + - type: Surgery + requirement: + - SurgeryOpenIncision + steps: + - SurgeryStepInciseCartilage + - SurgeryStepExposeNerves + - SurgeryStepExposeBloodVessels + - SurgeryAmputationStep + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Arm + - Hand + - Leg + - Foot + - Tail + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/saw.rsi + state: saw + +- type: entity + parent: SurgeryAmputation + id: SurgeryAmputationHead + name: Amputation + description: Surgical removal of a head. + components: + - type: Surgery + requirement: + - SurgeryOpenIncision + steps: + - SurgeryStepDeepIncision + - SurgeryStepExposeSkull + - SurgeryStepExposeNerves + - SurgeryStepExposeBloodVessels + - SurgeryStepSawSkull + - type: SurgeryPartCondition + parts: + - Head + +- type: entity + parent: SurgeryAmputation + id: SurgeryAmputationSlime + components: + - type: Surgery + requirement: + - SurgeryOpenIncisionSlime + steps: + - SurgeryStepDeepIncision + - SurgeryStepInciseCartilage + - SurgeryStepSawSkull + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + +- type: entity + parent: SurgeryAmputationHead + id: SurgeryAmputationHeadSlime + components: + - type: Surgery + requirement: + - SurgeryOpenIncisionSlime + steps: + - SurgeryStepDeepIncision + - SurgeryStepInciseCartilage + - SurgeryStepHeadFinalizeSeparation + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson diff --git a/Resources/Prototypes/_Sunrise/Surgery/attachment_steps.yml b/Resources/Prototypes/_Sunrise/Surgery/attachment_steps.yml index 59ed056597..acfd76446e 100644 --- a/Resources/Prototypes/_Sunrise/Surgery/attachment_steps.yml +++ b/Resources/Prototypes/_Sunrise/Surgery/attachment_steps.yml @@ -1,32 +1,4 @@ - type: entity - parent: SurgeryStepBase - id: SurgeryStepExposeNerves - name: Expose Nerves - components: - - type: SurgeryStep - duration: 4 - tools: - - type: Scalpel - - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scalpel.rsi - state: scalpel - - type: SurgeryStepEmoteEffect - -- type: entity - parent: SurgeryStepBase - id: SurgeryStepExposeBloodVessels - name: Expose Blood Vessels - components: - - type: SurgeryStep - duration: 4 - tools: - - type: Scalpel - - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scalpel.rsi - state: scalpel - - type: SurgeryStepEmoteEffect - -- type: entity parent: SurgeryStepBase id: SurgeryLimbAttachmentStep name: attach a limb @@ -34,7 +6,7 @@ - type: SurgeryStep duration: 4 tools: - - type: BodyPart + - type: MetaData - type: Sprite sprite: Objects/Consumable/Food/Baked/pizza.rsi state: meat-slice diff --git a/Resources/Prototypes/_Sunrise/Surgery/attachment_surgeries.yml b/Resources/Prototypes/_Sunrise/Surgery/attachment_surgeries.yml new file mode 100644 index 0000000000..52719f94b0 --- /dev/null +++ b/Resources/Prototypes/_Sunrise/Surgery/attachment_surgeries.yml @@ -0,0 +1,223 @@ +- type: entity + parent: SurgeryBase + id: SurgeryLimbAttachmentHead + name: Limb Attachment Head + description: Surgical attachment of a limb. + components: + - type: Surgery + requirement: + - SurgeryOpenIncision + steps: + - SurgeryStepExposeNerves + - SurgeryStepExposeBloodVessels + - SurgeryLimbAttachmentStep + - SurgeryStepRejoinNerves + - SurgeryStepRejoinBloodVessels + - SurgeryStepRestoreCartilage + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + - type: SurgeryLimbSlotCondition + slot: head + - type: Sprite + sprite: Objects/Specific/Medical/medical.rsi + state: medicated-suture + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentLeftArm + name: Limb Attachment Left Arm + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left arm + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentLeftHand + name: Limb Attachment Left Hand + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left hand + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentRightArm + name: Limb Attachment Right Arm + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right arm + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentRightHand + name: Limb Attachment Right Hand + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right hand + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentLeftLeg + name: Limb Attachment Left Leg + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left leg + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentLeftFoot + name: Limb Attachment Left Foot + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left foot + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentRightLeg + name: Limb Attachment Right Leg + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right leg + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentRightFoot + name: Limb Attachment Right Foot + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right foot + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentTail + name: Limb Attachment Tail + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: tail + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentOther + name: Limb Attachment Other + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: other + +#SlimePerson + +- type: entity + parent: SurgeryLimbAttachmentHead + id: SurgeryLimbAttachmentSlimeHead + components: + - type: Surgery + requirement: + - SurgeryOpenIncisionSlime + steps: + - SurgeryStepDeepIncision + - SurgeryLimbAttachmentStep + - SurgeryStepRestoreCartilage + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeLeftArm + name: Limb Attachment Left Arm + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left arm + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeLeftHand + name: Limb Attachment Left Hand + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left hand + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeRightArm + name: Limb Attachment Right Arm + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right arm + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeRightHand + name: Limb Attachment Right Hand + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right hand + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeLeftLeg + name: Limb Attachment Left Leg + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left leg + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeLeftFoot + name: Limb Attachment Left Foot + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: left foot + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeRightLeg + name: Limb Attachment Right Leg + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right leg + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeRightFoot + name: Limb Attachment Right Foot + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: right foot + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeTail + name: Limb Attachment Tail + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: tail + +- type: entity + parent: SurgeryLimbAttachmentSlimeHead + id: SurgeryLimbAttachmentSlimeOther + name: Limb Attachment Other + description: Surgical attachment of a limb. + components: + - type: SurgeryLimbSlotCondition + slot: other \ No newline at end of file diff --git a/Resources/Prototypes/_Sunrise/Surgery/common_steps.yml b/Resources/Prototypes/_Sunrise/Surgery/common_steps.yml new file mode 100644 index 0000000000..eb679f65a1 --- /dev/null +++ b/Resources/Prototypes/_Sunrise/Surgery/common_steps.yml @@ -0,0 +1,72 @@ +- type: entity + parent: SurgeryStepBase + id: SurgeryStepExposeNerves + name: Expose Nerves + components: + - type: SurgeryStep + duration: 4 + tools: + - type: Scalpel + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scalpel.rsi + state: scalpel + - type: SurgeryStepEmoteEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepExposeBloodVessels + name: Expose Blood Vessels + components: + - type: SurgeryStep + duration: 4 + tools: + - type: Scalpel + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scalpel.rsi + state: scalpel + - type: SurgeryStepEmoteEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepDeepIncision + name: Deep Incision + components: + - type: SurgeryStep + duration: 5 + tools: + - type: Scalpel + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scalpel.rsi + state: scalpel + - type: SurgeryStepEmoteEffect + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepRetractSkin + name: Retract the skin + components: + - type: SurgeryStep + tools: + - type: Retractor + add: + - type: SkinRetracted + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scissors.rsi + state: retractor + +- type: entity + parent: SurgeryStepRetractSkin + id: SurgeryStepRetractMembrane + name: Retract the membrane + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepCoagulateJellyFlow + name: Coagulate Jelly Flow + components: + - type: SurgeryStep + tools: + - type: Hemostat + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scissors.rsi + state: hemostat \ No newline at end of file diff --git a/Resources/Prototypes/_Sunrise/Surgery/organs_steps.yml b/Resources/Prototypes/_Sunrise/Surgery/organs_steps.yml index ee2ac1dc8b..7a6d39b3a4 100644 --- a/Resources/Prototypes/_Sunrise/Surgery/organs_steps.yml +++ b/Resources/Prototypes/_Sunrise/Surgery/organs_steps.yml @@ -574,7 +574,7 @@ state: hemostat # kidneys - + - type: entity parent: SurgeryStepBase id: SurgeryStepPrepareImplantSiteKidneys @@ -619,7 +619,7 @@ state: hemostat # stomach - + - type: entity parent: SurgeryStepBase id: SurgeryStepPrepareImplantSiteStomach @@ -662,7 +662,7 @@ state: hemostat # lungs - + - type: entity parent: SurgeryStepBase id: SurgeryStepPrepareImplantSiteLungs @@ -705,7 +705,7 @@ state: hemostat # heart - + - type: entity parent: SurgeryStepBase id: SurgeryStepPrepareImplantSiteHeart @@ -984,4 +984,62 @@ state: cautery - type: SurgeryClearProgress +# Cavity +- type: entity + parent: SurgeryStepBase + id: SurgeryStepLocateItemCavity + name: Locate Item + components: + - type: SurgeryStep + duration: 3 + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: torso_m + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepRemoveItemCavity + name: Remove Item + components: + - type: SurgeryStep + duration: 6 + tools: + - type: Scalpel + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: torso_m + - type: SurgeryStepEmoteEffect + - type: SurgeryStepOrganExtract + organ: + - type: Item + slot: cavity + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepPrepareImplantSiteCavity + name: Prepare Implant Site + components: + - type: SurgeryStep + duration: 4 + tools: + - type: Scalpel + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/scalpel.rsi + state: scalpel + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepInsertItemCavity + name: Insert Item + components: + - type: SurgeryStep + duration: 3 + tools: + - type: Item + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: torso_m + - type: SurgeryItemSizeCondition + - type: SurgeryStepOrganInsert + slot: cavity diff --git a/Resources/Prototypes/_Sunrise/Surgery/surgeries.yml b/Resources/Prototypes/_Sunrise/Surgery/surgeries.yml index 003ba7b023..8e7fa1e08f 100644 --- a/Resources/Prototypes/_Sunrise/Surgery/surgeries.yml +++ b/Resources/Prototypes/_Sunrise/Surgery/surgeries.yml @@ -14,6 +14,24 @@ - SurgeryStepOpenIncisionScalpel - SurgeryStepClampBleeders - SurgeryStepRetractSkin + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + +- type: entity + parent: SurgeryOpenIncision + id: SurgeryOpenIncisionSlime + components: + - type: Surgery + priority: -100 + steps: + - SurgeryStepOpenIncisionScalpel + - SurgeryStepCoagulateJellyFlow + - SurgeryStepRetractMembrane + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson - type: entity parent: SurgeryBase @@ -21,12 +39,32 @@ name: Close Incision components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision priority: 100 steps: - SurgeryStepCloseBones - SurgeryStepMendRibcage - SurgeryStepCloseIncision + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + +- type: entity + parent: SurgeryCloseIncision + id: SurgeryCloseIncisionSlime + components: + - type: Surgery + requirement: + - SurgeryOpenIncisionSlime + priority: 100 + steps: + - SurgeryStepMendRibcage + - SurgeryStepCloseIncision + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson - type: entity parent: SurgeryBase @@ -34,25 +72,31 @@ name: Open Ribcage components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision priority: -50 steps: - SurgeryStepSawBones - SurgeryStepPriseOpenBones - type: SurgeryPartCondition - parts: + parts: - Torso + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: Sprite - sprite: Mobs/Species/Human/parts.rsi + sprite: Mobs/Species/Skeleton/parts.rsi state: torso_m - + - type: entity parent: SurgeryBase id: SurgeryOpenAbdomen name: Open Abdomen components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision + - SurgeryOpenIncisionSlime priority: -50 steps: - SurgeryStepCutAbdominalMuscles @@ -61,71 +105,31 @@ parts: - Torso - type: Sprite - sprite: Mobs/Species/Skeleton/parts.rsi + sprite: Mobs/Species/Human/parts.rsi state: torso_m - type: entity parent: SurgeryBase id: SurgeryEliminateVocalCordDefects - name: Eliminate vocal cord defects. + name: Eliminate vocal cord defects description: Remove speech defects, accents. components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision + - SurgeryOpenIncisionSlime steps: - SurgeryStepExposeVocalCords - SurgeryStepAdjustVocalCords - SurgeryStepSutureIncision - type: SurgeryAnyAccentCondition - type: SurgeryPartCondition - parts: + parts: - Head - type: Sprite sprite: Objects/Fun/Instruments/microphone.rsi state: icon -- type: entity - parent: SurgeryBase - id: SurgeryAmputation - name: Amputation - description: Surgical removal of a limb. - components: - - type: Surgery - requirement: SurgeryOpenIncision - steps: - - SurgeryStepExposeNerves - - SurgeryStepExposeBloodVessels - - SurgeryAmputationStep - - type: SurgeryPartCondition - parts: - - Arm - - Hand - - Leg - - Foot - - Tail - - type: Sprite - sprite: Objects/Specific/Medical/Surgery/saw.rsi - state: saw - -- type: entity - parent: SurgeryBase - id: SurgeryLimbAttachment - name: Limb Attachment - description: Surgical attachment of a limb. - components: - - type: Surgery - requirement: SurgeryOpenIncision - steps: - - SurgeryStepExposeNerves - - SurgeryStepExposeBloodVessels - - SurgeryLimbAttachmentStep - - SurgeryStepRejoinNerves - - SurgeryStepRejoinBloodVessels - - SurgeryStepRestoreCartilage - - type: SurgeryAnyLimbSlotCondition - - type: Sprite - sprite: Objects/Specific/Medical/medical.rsi - state: medicated-suture #organs - type: entity @@ -134,11 +138,15 @@ name: Extract Liver components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepLocateLiver - SurgeryStepClampLiverVessels - SurgeryStepRemoveLiver + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -148,20 +156,24 @@ - type: Sprite sprite: Mobs/Species/Human/organs.rsi state: liver - + - type: entity parent: SurgeryBase id: SurgeryImplantLiver name: Implant Liver components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepPrepareImplantSiteLiver - SurgeryStepInsertLiver - SurgeryStepConnectLiverVessels - SurgeryStepRestoreAbdominalWalls - SurgeryStepSutureMuscles + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -178,11 +190,15 @@ name: Extract Appendix components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepLocateAppendix - SurgeryStepClampAppendix - SurgeryStepRemoveAppendix + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -199,11 +215,15 @@ name: Extract Kidneys components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepLocateKidneys - SurgeryStepClampKidneysVessels - SurgeryStepRemoveKidneys + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -222,13 +242,17 @@ name: Implant Kidneys components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepPrepareImplantSiteKidneys - SurgeryStepInsertKidneys - SurgeryStepConnectKidneysVessels - SurgeryStepRestoreAbdominalWalls - SurgeryStepSutureMuscles + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -247,11 +271,15 @@ name: Extract Stomach components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepLocateStomach - SurgeryStepClampStomachVessels - SurgeryStepRemoveStomach + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -268,13 +296,17 @@ name: Implant Stomach components: - type: Surgery - requirement: SurgeryOpenAbdomen + requirement: + - SurgeryOpenAbdomen steps: - SurgeryStepPrepareImplantSiteStomach - SurgeryStepInsertStomach - SurgeryStepConnectStomachVessels - SurgeryStepRestoreAbdominalWalls - SurgeryStepSutureMuscles + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -291,11 +323,15 @@ name: Extract Lungs components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: + - SurgeryOpenRibcage steps: - SurgeryStepLocateLungs - SurgeryStepClampLungVessels - SurgeryStepRemoveLungs + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -314,11 +350,71 @@ name: Implant Lungs components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: + - SurgeryOpenRibcage steps: - SurgeryStepPrepareImplantSiteLungs - SurgeryStepInsertLungs - SurgeryStepConnectLungVessels + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganDontExistCondition + organ: + - type: OrganLungs + - type: Sprite + sprite: Mobs/Species/Human/organs.rsi + layers: + - state: lung-l + - state: lung-r + +- type: entity + parent: SurgeryBase + id: SurgeryExtractLungsSlime + name: Extract Lungs + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepLocateLungs + - SurgeryStepClampLungVessels + - SurgeryStepRemoveLungs + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganExistCondition + organ: + - type: OrganLungs + - type: Sprite + sprite: Mobs/Species/Human/organs.rsi + layers: + - state: lung-l + - state: lung-r + +- type: entity + parent: SurgeryBase + id: SurgeryImplantLungsSlime + name: Implant Lungs + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepPrepareImplantSiteLungs + - SurgeryStepInsertLungs + - SurgeryStepConnectLungVessels + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -337,11 +433,15 @@ name: Extract Heart components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: + - SurgeryOpenRibcage steps: - SurgeryStepLocateHeart - SurgeryStepClampHeartVessels - SurgeryStepRemoveHeart + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -358,11 +458,15 @@ name: Implant Heart components: - type: Surgery - requirement: SurgeryOpenRibcage + requirement: + - SurgeryOpenRibcage steps: - SurgeryStepPrepareImplantSiteHeart - SurgeryStepInsertHeart - SurgeryStepConnectHeartVessels + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Torso @@ -373,13 +477,65 @@ sprite: Mobs/Species/Human/organs.rsi state: heart-on # +- type: entity + parent: SurgeryExtractHeart + id: SurgeryExtractHeartSlime + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepLocateHeart + - SurgeryStepClampHeartVessels + - SurgeryStepRemoveHeart + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganExistCondition + organ: + - type: OrganHeart + - type: Sprite + sprite: _Sunrise/Mobs/Species/Slime/organs.rsi + state: heart-on + +- type: entity + parent: SurgeryImplantHeart + id: SurgeryImplantHeartSlime + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepPrepareImplantSiteHeart + - SurgeryStepInsertHeart + - SurgeryStepConnectHeartVessels + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganDontExistCondition + organ: + - type: OrganHeart + - type: Sprite + sprite: _Sunrise/Mobs/Species/Slime/organs.rsi + state: heart-on +# - type: entity parent: SurgeryBase id: SurgeryExtractEyes name: Extract Eyes components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision + - SurgeryOpenIncisionSlime steps: - SurgeryStepLocateEyes - SurgeryStepClampOpticNerve @@ -402,7 +558,9 @@ name: Implant Eyes components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision + - SurgeryOpenIncisionSlime steps: - SurgeryStepPrepareImplantSiteEyes - SurgeryStepInsertEyes @@ -464,7 +622,8 @@ name: Extract Brain components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision steps: - SurgeryStepPreparePatient - SurgeryStepShaveHead @@ -479,6 +638,9 @@ - SurgeryStepRetractDuraMater - SurgeryStepSeverCranialNerves - SurgeryStepExtractBrain + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Head @@ -495,7 +657,8 @@ name: Implant Brain components: - type: Surgery - requirement: SurgeryOpenIncision + requirement: + - SurgeryOpenIncision steps: - SurgeryStepCleanImplantSite - SurgeryStepPrepareScalp @@ -515,6 +678,9 @@ - SurgeryStepSecureBoneFlap - SurgeryStepReplaceScalp - SurgeryStepSutureScalp + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson - type: SurgeryPartCondition parts: - Head @@ -524,3 +690,112 @@ - type: Sprite sprite: Mobs/Species/Human/organs.rsi state: brain + +# +- type: entity + parent: SurgeryBase + id: SurgeryExtractCore + name: Extract Core + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepPreparePatient + - SurgeryStepDisinfectScalp + - SurgeryStepMakeIncisionScalp + - SurgeryStepRetractScalp + - SurgeryStepExtractBrain + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganExistCondition + organ: + - type: OrganBrain + - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi + state: brain-slime + +- type: entity + parent: SurgeryBase + id: SurgeryImplantCore + name: Implant Core + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepCleanImplantSite + - SurgeryStepPrepareScalp + - SurgeryStepMakeIncisionScalp + - SurgeryStepRetractScalp + - SurgeryStepInsertBrain + - SurgeryStepReplaceScalp + - SurgeryStepSutureScalp + - type: SurgerySpeciesCondition + speciesBlacklist: [] + speciesWhitelist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganDontExistCondition + organ: + - type: OrganBrain + - type: Sprite + sprite: Mobs/Species/Slime/organs.rsi + state: brain-slime +# +- type: entity + parent: SurgeryBase + id: SurgeryExtractCavityItem + name: Extract Item + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepLocateItemCavity + - SurgeryStepRemoveItemCavity + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganExistCondition + organ: + - type: Item + container: cavity + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: torso_m + +- type: entity + parent: SurgeryBase + id: SurgeryImplantCavityItem + name: Implant Item + components: + - type: Surgery + requirement: + - SurgeryOpenAbdomen + steps: + - SurgeryStepPrepareImplantSiteCavity + - SurgeryStepInsertItemCavity + - type: SurgerySpeciesCondition + speciesBlacklist: + - SlimePerson + - type: SurgeryPartCondition + parts: + - Torso + - type: SurgeryOrganDontExistCondition + organ: + - type: Item + container: cavity + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + state: torso_m diff --git a/Resources/Prototypes/_Sunrise/Surgery/surgery_steps.yml b/Resources/Prototypes/_Sunrise/Surgery/surgery_steps.yml index 31cdd183ad..f5553eee62 100644 --- a/Resources/Prototypes/_Sunrise/Surgery/surgery_steps.yml +++ b/Resources/Prototypes/_Sunrise/Surgery/surgery_steps.yml @@ -39,20 +39,6 @@ state: hemostat - type: SurgeryClampBleedEffect -- type: entity - parent: SurgeryStepBase - id: SurgeryStepRetractSkin - name: Retract the skin - components: - - type: SurgeryStep - tools: - - type: Retractor - add: - - type: SkinRetracted - - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi - state: retractor - - type: entity parent: SurgeryStepBase id: SurgeryStepSawBones diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_arm.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_arm.png new file mode 100644 index 0000000000..b240222637 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_arm.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_foot.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_foot.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_foot.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_hand.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_hand.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_hand.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_leg.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_leg.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/l_leg.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/meta.json b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/meta.json new file mode 100644 index 0000000000..3cfd1efef8 --- /dev/null +++ b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/meta.json @@ -0,0 +1,46 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "starlight", + "size": { + "x": 32, + "y": 32 + }, + "load": { + "srgb": false + }, + "states": [ + { + "name": "l_arm", + "directions": 4 + }, + { + "name": "r_arm", + "directions": 4 + }, + { + "name": "l_foot", + "directions": 4 + }, + { + "name": "r_foot", + "directions": 4 + }, + { + "name": "l_leg", + "directions": 4 + }, + { + "name": "r_leg", + "directions": 4 + }, + { + "name": "l_hand", + "directions": 4 + }, + { + "name": "r_hand", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_arm.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_arm.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_arm.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_foot.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_foot.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_foot.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_hand.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_hand.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_hand.png differ diff --git a/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_leg.png b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_leg.png new file mode 100644 index 0000000000..fab42cb9f9 Binary files /dev/null and b/Resources/Textures/_Sunrise/CustomLimb/displacement.rsi/r_leg.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/eyes.png b/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/eyes.png new file mode 100644 index 0000000000..35cf206bf1 Binary files /dev/null and b/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/eyes.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/meta.json b/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/meta.json index 166be56b5e..b2014e89ff 100644 --- a/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/meta.json +++ b/Resources/Textures/_Sunrise/Mobs/Species/Cyberlimbs/parts.rsi/meta.json @@ -112,6 +112,10 @@ "name": "r_foot", "directions": 4 }, + { + "name": "eyes", + "directions": 4 + }, { "name": "r_hand", "directions": 4, diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-left.png b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-left.png new file mode 100644 index 0000000000..1d73edaf03 Binary files /dev/null and b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-left.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-right.png b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-right.png new file mode 100644 index 0000000000..3f7ace9b48 Binary files /dev/null and b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-inhand-right.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-off.png b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-off.png new file mode 100644 index 0000000000..da49e09066 Binary files /dev/null and b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-off.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-on.png b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-on.png new file mode 100644 index 0000000000..0f2e286f28 Binary files /dev/null and b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/heart-on.png differ diff --git a/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/meta.json b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/meta.json new file mode 100644 index 0000000000..35c260a560 --- /dev/null +++ b/Resources/Textures/_Sunrise/Mobs/Species/Slime/organs.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by Nimfar11 (Github) for Space Station 14, inhands by mubururu_ (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "heart-off" + }, + { + "name": "heart-on", + "delays": [ + [ + 0.6, + 0.1, + 0.1 + ] + ] + }, + { + "name": "heart-inhand-left", + "directions": 4 + }, + { + "name": "heart-inhand-right", + "directions": 4 + } + ] +}