using System.Linq; using Content.Server.Body.Systems; using Content.Server.Chat.Systems; using Content.Server.Popups; using Content.Shared.Body.Part; using Content.Shared.Starlight.Medical.Surgery; using Content.Shared.Starlight.Medical.Surgery.Effects.Step; using Content.Shared.Starlight.Medical.Surgery.Events; using Content.Shared.Damage; using Content.Shared.Interaction; using Content.Shared.Prototypes; using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Utility; using Content.Server.Administration.Systems; using Content.Shared.Damage.Systems; namespace Content.Server.Starlight.Medical.Surgery; // Based on the RMC14. // https://github.com/RMC-14/RMC-14 public sealed partial class SurgerySystem : SharedSurgerySystem { [Dependency] private readonly BodySystem _body = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly IPrototypeManager _prototypes = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly ContainerSystem _containers = default!; private readonly List _surgeries = []; public override void Initialize() { base.Initialize(); InitializeSteps(); SubscribeLocalEvent(OnToolAfterInteract); SubscribeLocalEvent(OnPrototypesReloaded); LoadPrototypes(); } protected override void RefreshUI(EntityUid body) { if (!HasComp(body)) return; var surgeries = new Dictionary>(); if (HasComp(body)) { AddSurgeries(body, body, surgeries); } else { foreach (var part in _body.GetBodyChildren(body)) { 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 (!_entity.TryGetSingleton(surgery, out var 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; if (args.Handled || !args.CanReach || args.Target == null || _ui.IsUiOpen(user, SurgeryUIKey.Key, user) || !HasComp(args.Target)) return; if (user == args.Target) { _popup.PopupEntity("You can't perform surgery on yourself!", user, user); return; } args.Handled = true; _ui.OpenUi(args.Target.Value, SurgeryUIKey.Key, user); RefreshUI(args.Target.Value); } private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) { if (args.WasModified()) LoadPrototypes(); } private void LoadPrototypes() { _surgeries.Clear(); foreach (var entity in _prototypes.EnumeratePrototypes()) { if (entity.HasComponent()) _surgeries.Add(new EntProtoId(entity.ID)); } } }