| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // SPDX-FileCopyrightText: 2024 Piras314 <p1r4s@proton.me>
- // SPDX-FileCopyrightText: 2024 deltanedas <39013340+deltanedas@users.noreply.github.com>
- // SPDX-FileCopyrightText: 2024 deltanedas <@deltanedas:kde.org>
- // SPDX-FileCopyrightText: 2024 gluesniffler <159397573+gluesniffler@users.noreply.github.com>
- // SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
- // SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
- // SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
- //
- // SPDX-License-Identifier: AGPL-3.0-or-later
- using Content.Server.Atmos.Rotting;
- using Content.Server.Body.Systems;
- using Content.Server.Chat.Systems;
- using Content.Shared.Body.Part;
- using Content.Server.Popups;
- using Content.Shared.Bed.Sleep;
- using Content.Shared.Damage;
- using Content.Shared.Eye.Blinding.Systems;
- using Content.Shared._Shitmed.Medical.Surgery;
- using Content.Shared._Shitmed.Medical.Surgery.Conditions;
- using Content.Shared._Shitmed.Medical.Surgery.Effects.Step;
- using Content.Shared._Shitmed.Medical.Surgery.Tools;
- using Robust.Server.GameObjects;
- using Robust.Shared.Configuration;
- using Robust.Shared.Prototypes;
- using Robust.Shared.Utility;
- using Content.Shared.Verbs;
- namespace Content.Server._Shitmed.Medical.Surgery;
- public sealed class SurgerySystem : SharedSurgerySystem
- {
- [Dependency] private readonly BodySystem _body = default!;
- [Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly IConfigurationManager _config = default!;
- [Dependency] private readonly DamageableSystem _damageable = default!;
- [Dependency] private readonly IPrototypeManager _prototypes = default!;
- [Dependency] private readonly PopupSystem _popup = default!;
- [Dependency] private readonly UserInterfaceSystem _ui = default!;
- [Dependency] private readonly RottingSystem _rot = default!;
- [Dependency] private readonly BlindableSystem _blindableSystem = default!;
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent<SurgeryToolComponent, GetVerbsEvent<UtilityVerb>>(OnUtilityVerb);
- SubscribeLocalEvent<SurgeryTargetComponent, SurgeryStepDamageEvent>(OnSurgeryStepDamage);
- // You might be wondering "why aren't we using StepEvent for these two?" reason being that StepEvent fires off regardless of success on the previous functions
- // so this would heal entities even if you had a used or incorrect organ.
- SubscribeLocalEvent<SurgerySpecialDamageChangeEffectComponent, SurgeryStepDamageChangeEvent>(OnSurgerySpecialDamageChange);
- SubscribeLocalEvent<SurgeryDamageChangeEffectComponent, SurgeryStepDamageChangeEvent>(OnSurgeryDamageChange);
- SubscribeLocalEvent<SurgeryStepEmoteEffectComponent, SurgeryStepEvent>(OnStepScreamComplete);
- SubscribeLocalEvent<SurgeryStepSpawnEffectComponent, SurgeryStepEvent>(OnStepSpawnComplete);
- }
- protected override void RefreshUI(EntityUid body)
- {
- var surgeries = new Dictionary<NetEntity, List<EntProtoId>>();
- foreach (var surgery in AllSurgeries)
- {
- if (GetSingleton(surgery) is not { } surgeryEnt)
- continue;
- foreach (var part in _body.GetBodyChildren(body))
- {
- var ev = new SurgeryValidEvent(body, part.Id);
- RaiseLocalEvent(surgeryEnt, ref ev);
- if (ev.Cancelled)
- continue;
- surgeries.GetOrNew(GetNetEntity(part.Id)).Add(surgery);
- }
- }
- _ui.SetUiState(body, SurgeryUIKey.Key, new SurgeryBuiState(surgeries));
- /*
- Reason we do this is because when applying a BUI State, it rolls back the state on the entity temporarily,
- which just so happens to occur right as we're checking for step completion, so we end up with the UI
- not updating at all until you change tools or reopen the window. I love shitcode.
- */
- _ui.ServerSendUiMessage(body, SurgeryUIKey.Key, new SurgeryBuiRefreshMessage());
- }
- private void SetDamage(EntityUid body,
- DamageSpecifier damage,
- float partMultiplier,
- EntityUid user,
- EntityUid part)
- {
- if (!TryComp<BodyPartComponent>(part, out var partComp))
- return;
- _damageable.TryChangeDamage(body,
- damage,
- true,
- origin: user,
- canSever: false,
- partMultiplier: partMultiplier,
- targetPart: _body.GetTargetBodyPart(partComp));
- }
- private void AttemptStartSurgery(Entity<SurgeryToolComponent> ent, EntityUid user, EntityUid target)
- {
- if (!IsLyingDown(target, user))
- return;
- if (user == target)
- {
- _popup.PopupEntity(Loc.GetString("surgery-error-self-surgery"), user, user);
- return;
- }
- _ui.OpenUi(target, SurgeryUIKey.Key, user);
- RefreshUI(target);
- }
- private void OnUtilityVerb(Entity<SurgeryToolComponent> ent, ref GetVerbsEvent<UtilityVerb> args)
- {
- if (!args.CanInteract
- || !args.CanAccess
- || !HasComp<SurgeryTargetComponent>(args.Target))
- return;
- var user = args.User;
- var target = args.Target;
- var verb = new UtilityVerb()
- {
- Act = () => AttemptStartSurgery(ent, user, target),
- Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/"), "scalpel"),
- Text = Loc.GetString("surgery-verb-text"),
- Message = Loc.GetString("surgery-verb-message"),
- DoContactInteraction = true
- };
- args.Verbs.Add(verb);
- }
- private void OnSurgeryStepDamage(Entity<SurgeryTargetComponent> ent, ref SurgeryStepDamageEvent args) =>
- SetDamage(args.Body, args.Damage, args.PartMultiplier, args.User, args.Part);
- private void OnSurgeryDamageChange(Entity<SurgeryDamageChangeEffectComponent> ent, ref SurgeryStepDamageChangeEvent args)
- {
- var damageChange = ent.Comp.Damage;
- if (HasComp<ForcedSleepingComponent>(args.Body))
- damageChange = damageChange * ent.Comp.SleepModifier;
- SetDamage(args.Body, damageChange, 0.5f, args.User, args.Part);
- }
- private void OnSurgerySpecialDamageChange(Entity<SurgerySpecialDamageChangeEffectComponent> ent, ref SurgeryStepDamageChangeEvent args)
- {
- // Im killing this shit soon too, inshallah.
- if (ent.Comp.DamageType == "Rot")
- _rot.ReduceAccumulator(args.Body, TimeSpan.FromSeconds(2147483648)); // BEHOLD, SHITCODE THAT I JUST COPY PASTED. I'll redo it at some point, pinky swear :)
- /*else if (ent.Comp.DamageType == "Eye"
- && TryComp(ent, out BlindableComponent? blindComp)
- && blindComp.EyeDamage > 0)
- _blindableSystem.AdjustEyeDamage((args.Body, blindComp), -blindComp!.EyeDamage);*/
- }
- private void OnStepScreamComplete(Entity<SurgeryStepEmoteEffectComponent> ent, ref SurgeryStepEvent args)
- {
- if (HasComp<ForcedSleepingComponent>(args.Body))
- return;
- _chat.TryEmoteWithChat(args.Body, ent.Comp.Emote);
- }
- private void OnStepSpawnComplete(Entity<SurgeryStepSpawnEffectComponent> ent, ref SurgeryStepEvent args) =>
- SpawnAtPosition(ent.Comp.Entity, Transform(args.Body).Coordinates);
- }
|