// SPDX-FileCopyrightText: 2025 GoobBot // SPDX-FileCopyrightText: 2025 Solstice // SPDX-FileCopyrightText: 2025 SolsticeOfTheWinter // SPDX-FileCopyrightText: 2025 gus // // SPDX-License-Identifier: AGPL-3.0-or-later using Content.Shared._Goobstation.CheatDeath; using Content.Shared._Goobstation.Devil; using Content.Shared._Goobstation.Devil.Condemned; using Content.Shared.Mobs.Components; using Content.Shared.Verbs; using Robust.Shared.Utility; namespace Content.Server._Goobstation.Devil; public sealed partial class DevilSystem { private void InitializeHandshakeSystem() { SubscribeLocalEvent>(OnGetVerbs); SubscribeLocalEvent>(OnGetVerbsPending); } private void OnGetVerbs(EntityUid uid, DevilComponent comp, GetVerbsEvent args) { // Can't shake your own hand, and you can't shake from a distance if (!args.CanAccess || !args.CanInteract || _state.IsIncapacitated(args.Target) || !HasComp(args.Target) || args.Target == args.User || HasComp(args.Target)) return; InnateVerb handshakeVerb = new() { Act = () => OfferHandshake(args.User, args.Target), Text = Loc.GetString("hand-shake-prompt-verb", ("target", args.Target)), Icon = new SpriteSpecifier.Rsi(new("_Goobstation/Actions/devil.rsi"), "summon-contract"), Priority = 1 // Higher priority than default verbs }; args.Verbs.Add(handshakeVerb); } private void OnGetVerbsPending(EntityUid uid, PendingHandshakeComponent comp, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || _state.IsIncapacitated(args.Target) || !HasComp(args.Target) || args.Target != comp.Offerer) return; InnateVerb handshakeVerb = new() { Act = () => HandleHandshake(args.Target, args.User), Text = Loc.GetString("hand-shake-accept-verb", ("target", args.Target)), Icon = new SpriteSpecifier.Rsi(new("_Goobstation/Actions/devil.rsi"), "summon-contract"), Priority = 1 // Higher priority than default verbs }; args.Verbs.Add(handshakeVerb); } private void OfferHandshake(EntityUid user, EntityUid target) { if (HasComp(target) || HasComp(target)) return; var pending = AddComp(target); pending.Offerer = user; pending.ExpiryTime = _timing.CurTime + TimeSpan.FromSeconds(15); // Notify target var popupMessage = Loc.GetString("handshake-offer-popup", ("user", user)); _popup.PopupEntity(popupMessage, target, target); // Notify self var selfPopup = Loc.GetString("handshake-offer-popup-self", ("target", target)); _popup.PopupEntity(selfPopup, user, user); } private void HandleHandshake(EntityUid user, EntityUid target) { if (!_contract.TryTransferSouls(user, target, 1)) { var handshakeFail = Loc.GetString("handshake-fail", ("user", user)); _popup.PopupEntity(handshakeFail, user, user); return; } var handshakeSucess = Loc.GetString("handshake-success", ("user", user)); _popup.PopupEntity(handshakeSucess, target, target); _rejuvenate.PerformRejuvenate(target); var cheatdeath = EnsureComp(target); cheatdeath.ReviveAmount = 1; _contract.AddRandomNegativeClause(target); } public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp)) { if (comp.ExpiryTime > _timing.CurTime) continue; RemCompDeferred(uid, comp); } } }