CatStation/Content.Server/Administration/Systems/AdminVerbSystem.cs
Dmitry 25c5e59248
Upstream (#3172)
Signed-off-by: Prole <172158352+Prole0@users.noreply.github.com>
Co-authored-by: PJBot <pieterjan.briers+bot@gmail.com>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: Samuka-C <47865393+Samuka-C@users.noreply.github.com>
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Co-authored-by: Partmedia <kevinz5000@gmail.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: themias <89101928+themias@users.noreply.github.com>
Co-authored-by: Victor Shen <71985089+Vexerot@users.noreply.github.com>
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: Kirus59 <145689588+Kirus59@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: Stomf <5dorkydorks@gmail.com>
Co-authored-by: drakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com>
Co-authored-by: PraxisMapper <praxismapper@gmail.com>
Co-authored-by: EmoGarbage404 <retron404@gmail.com>
Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Co-authored-by: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com>
Co-authored-by: TytosB <54259736+TytosB@users.noreply.github.com>
Co-authored-by: abadaba695 <spacestation13thingy@gmail.com>
Co-authored-by: kosticia <kosticia46@gmail.com>
Co-authored-by: Thinbug <101073555+Thinbug0@users.noreply.github.com>
Co-authored-by: pathetic meowmeow <uhhadd@gmail.com>
Co-authored-by: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Co-authored-by: Boaz1111 <149967078+Boaz1111@users.noreply.github.com>
Co-authored-by: ActiveMammmoth <140334666+ActiveMammmoth@users.noreply.github.com>
Co-authored-by: Myra <vasilis@pikachu.systems>
Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Co-authored-by: K-Dynamic <20566341+K-Dynamic@users.noreply.github.com>
Co-authored-by: Gentleman-Bird <dcgreen406@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: BIGZi0348 <svalker0348@gmail.com>
Co-authored-by: LaCumbiaDelCoronavirus <90893484+LaCumbiaDelCoronavirus@users.noreply.github.com>
Co-authored-by: imatsoup <93290208+imatsoup@users.noreply.github.com>
Co-authored-by: Matthew Herber <32679887+happyrobot33@users.noreply.github.com>
Co-authored-by: Ertanic <36124833+Ertanic@users.noreply.github.com>
Co-authored-by: MissKay1994 <15877268+MissKay1994@users.noreply.github.com>
Co-authored-by: Errant <35878406+Errant-4@users.noreply.github.com>
Co-authored-by: eoineoineoin <helloworld@eoinrul.es>
Co-authored-by: Tiniest Shark <head.rebel@yahoo.com>
Co-authored-by: nikitosych <boriszyn@gmail.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: Perry Fraser <perryprog@users.noreply.github.com>
Co-authored-by: YoungThug <ramialanbagy@gmail.com>
Co-authored-by: beck-thompson <107373427+beck-thompson@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: Southbridge <7013162+southbridge-fur@users.noreply.github.com>
Co-authored-by: Vladislav Suchkov <20380250+murolem@users.noreply.github.com>
Co-authored-by: Prole <172158352+Prole0@users.noreply.github.com>
Co-authored-by: Unkn0wn_Gh0st <shadowstalkermll@gmail.com>
Co-authored-by: 3nderall <101940324+3nderall@users.noreply.github.com>
Co-authored-by: Radezolid <snappednexus@gmail.com>
Co-authored-by: J <billsmith116@gmail.com>
Co-authored-by: Ghagliiarghii <68826635+Ghagliiarghii@users.noreply.github.com>
Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Co-authored-by: youtissoum <51883137+youtissoum@users.noreply.github.com>
Co-authored-by: Minemoder5000 <minemoder50000@gmail.com>
Co-authored-by: Spanky <scott@wearejacob.com>
Co-authored-by: Spessmann <156740760+Spessmann@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: brainfood1183 <113240905+brainfood1183@users.noreply.github.com>
Co-authored-by: Deerstop <edainturner@gmail.com>
Co-authored-by: B_Kirill <153602297+B-Kirill@users.noreply.github.com>
Co-authored-by: archee1 <archee3@hotmail.co.uk>
Co-authored-by: Cojoke <83733158+Cojoke-dot@users.noreply.github.com>
Co-authored-by: Quantum-cross <7065792+Quantum-cross@users.noreply.github.com>
Co-authored-by: poklj <compgeek223@gmail.com>
Co-authored-by: Krunklehorn <42424291+Krunklehorn@users.noreply.github.com>
Co-authored-by: OnyxTheBrave <131422822+OnyxTheBrave@users.noreply.github.com>
Co-authored-by: UpAndLeaves <92269094+Alpha-Two@users.noreply.github.com>
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
Co-authored-by: Zalycon <84675130+Zalycon@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: Verm <32827189+Vermidia@users.noreply.github.com>
Co-authored-by: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
Co-authored-by: Dmitry <57028746+dimm00n@users.noreply.github.com>
2025-05-24 11:00:17 +03:00

624 lines
28 KiB
C#

using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Server.Administration.UI;
using Content.Server.Disposal.Tube;
using Content.Server.EUI;
using Content.Server.Ghost.Roles;
using Content.Server.Mind.Commands;
using Content.Server.Mind;
using Content.Server.Prayer;
using Content.Server.Silicons.Laws;
using Content.Server.Station.Systems;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Configurable;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.GameTicking;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.Mind.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Popups;
using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Silicons.StationAi;
using Content.Shared.Verbs;
using Robust.Server.Console;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Toolshed;
using Robust.Shared.Utility;
using System.Linq;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Server.Administration.Systems
{
/// <summary>
/// System to provide various global admin/debug verbs
/// </summary>
public sealed partial class AdminVerbSystem : EntitySystem
{
[Dependency] private readonly IConGroupController _groupController = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly AdminSystem _adminSystem = default!;
[Dependency] private readonly DisposalTubeSystem _disposalTubes = default!;
[Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly PrayerSystem _prayerSystem = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly ToolshedManager _toolshed = default!;
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly StationSystem _stations = default!;
[Dependency] private readonly StationSpawningSystem _spawning = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly AdminFrozenSystem _freeze = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SiliconLawSystem _siliconLawSystem = default!;
private readonly Dictionary<ICommonSession, List<EditSolutionsEui>> _openSolutionUis = new();
public override void Initialize()
{
SubscribeLocalEvent<GetVerbsEvent<Verb>>(GetVerbs);
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
SubscribeLocalEvent<SolutionContainerManagerComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
}
private void GetVerbs(GetVerbsEvent<Verb> ev)
{
AddAdminVerbs(ev);
AddDebugVerbs(ev);
AddSmiteVerbs(ev);
AddTricksVerbs(ev);
AddAntagVerbs(ev);
}
private void AddAdminVerbs(GetVerbsEvent<Verb> args)
{
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;
var player = actor.PlayerSession;
if (_adminManager.IsAdmin(player))
{
Verb mark = new();
mark.Text = Loc.GetString("toolshed-verb-mark");
mark.Message = Loc.GetString("toolshed-verb-mark-description");
mark.Category = VerbCategory.Admin;
mark.Act = () => _toolshed.InvokeCommand(player, "=> $marked", new List<EntityUid> {args.Target}, out _);
mark.Impact = LogImpact.Low;
args.Verbs.Add(mark);
if (TryComp(args.Target, out ActorComponent? targetActor))
{
// AdminHelp
Verb verb = new();
verb.Text = Loc.GetString("ahelp-verb-get-data-text");
verb.Category = VerbCategory.Admin;
verb.Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/gavel.svg.192dpi.png"));
verb.Act = () =>
_console.RemoteExecuteCommand(player, $"openahelp \"{targetActor.PlayerSession.UserId}\"");
verb.Impact = LogImpact.Low;
args.Verbs.Add(verb);
// Subtle Messages
Verb prayerVerb = new();
prayerVerb.Text = Loc.GetString("prayer-verbs-subtle-message");
prayerVerb.Category = VerbCategory.Admin;
prayerVerb.Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/pray.svg.png"));
prayerVerb.Act = () =>
{
_quickDialog.OpenDialog(player, "Subtle Message", "Message", "Popup Message", (string message, string popupMessage) =>
{
_prayerSystem.SendSubtleMessage(targetActor.PlayerSession, player, message, popupMessage == "" ? Loc.GetString("prayer-popup-subtle-default") : popupMessage);
});
};
prayerVerb.Impact = LogImpact.Low;
args.Verbs.Add(prayerVerb);
// Spawn - Like respawn but on the spot.
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("admin-player-actions-spawn"),
Category = VerbCategory.Admin,
Act = () =>
{
if (!_transformSystem.TryGetMapOrGridCoordinates(args.Target, out var coords))
{
_popup.PopupEntity(Loc.GetString("admin-player-spawn-failed"), args.User, args.User);
return;
}
var stationUid = _stations.GetOwningStation(args.Target);
var profile = _gameTicker.GetPlayerProfile(targetActor.PlayerSession);
var mobUid = _spawning.SpawnPlayerMob(coords.Value, null, profile, stationUid);
if (_mindSystem.TryGetMind(args.Target, out var mindId, out var mindComp))
_mindSystem.TransferTo(mindId, mobUid, true, mind: mindComp);
},
ConfirmationPopup = true,
Impact = LogImpact.High,
});
// Clone - Spawn but without the mind transfer, also spawns at the user's coordinates not the target's
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("admin-player-actions-clone"),
Category = VerbCategory.Admin,
Act = () =>
{
if (!_transformSystem.TryGetMapOrGridCoordinates(args.User, out var coords))
{
_popup.PopupEntity(Loc.GetString("admin-player-spawn-failed"), args.User, args.User);
return;
}
var stationUid = _stations.GetOwningStation(args.Target);
var profile = _gameTicker.GetPlayerProfile(targetActor.PlayerSession);
_spawning.SpawnPlayerMob(coords.Value, null, profile, stationUid);
},
ConfirmationPopup = true,
Impact = LogImpact.High,
});
// PlayerPanel
args.Verbs.Add(new Verb
{
Text = Loc.GetString("admin-player-actions-player-panel"),
Category = VerbCategory.Admin,
Act = () => _console.ExecuteCommand(player, $"playerpanel \"{targetActor.PlayerSession.UserId}\""),
Impact = LogImpact.Low
});
}
if (_mindSystem.TryGetMind(args.Target, out var mindId, out var mindComp) && mindComp.UserId != null)
{
// Erase
args.Verbs.Add(new Verb
{
Text = Loc.GetString("admin-verbs-erase"),
Message = Loc.GetString("admin-verbs-erase-description"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(
new("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
Act = () =>
{
_adminSystem.Erase(mindComp.UserId.Value);
},
Impact = LogImpact.Extreme,
ConfirmationPopup = true
});
// Respawn
args.Verbs.Add(new Verb
{
Text = Loc.GetString("admin-player-actions-respawn"),
Category = VerbCategory.Admin,
Act = () =>
{
_console.ExecuteCommand(player, $"respawn \"{mindComp.UserId}\"");
},
ConfirmationPopup = true,
// No logimpact as the command does it internally.
});
// Inspect mind
args.Verbs.Add(new Verb
{
Text = Loc.GetString("inspect-mind-verb-get-data-text"),
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/sentient.svg.192dpi.png")),
Category = VerbCategory.Debug,
Act = () => _console.RemoteExecuteCommand(player, $"vv {GetNetEntity(mindId)}"),
});
}
// Freeze
var frozen = TryComp<AdminFrozenComponent>(args.Target, out var frozenComp);
var frozenAndMuted = frozenComp?.Muted ?? false;
if (!frozen)
{
args.Verbs.Add(new Verb
{
Priority = -1, // This is just so it doesn't change position in the menu between freeze/unfreeze.
Text = Loc.GetString("admin-verbs-freeze"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/snow.svg.192dpi.png")),
Act = () =>
{
EnsureComp<AdminFrozenComponent>(args.Target);
},
Impact = LogImpact.Medium,
});
}
if (!frozenAndMuted)
{
// allow you to additionally mute someone when they are already frozen
args.Verbs.Add(new Verb
{
Priority = -1, // This is just so it doesn't change position in the menu between freeze/unfreeze.
Text = Loc.GetString("admin-verbs-freeze-and-mute"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/snow.svg.192dpi.png")),
Act = () =>
{
_freeze.FreezeAndMute(args.Target);
},
Impact = LogImpact.Medium,
});
}
if (frozen)
{
args.Verbs.Add(new Verb
{
Priority = -1, // This is just so it doesn't change position in the menu between freeze/unfreeze.
Text = Loc.GetString("admin-verbs-unfreeze"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/snow.svg.192dpi.png")),
Act = () =>
{
RemComp<AdminFrozenComponent>(args.Target);
},
Impact = LogImpact.Medium,
});
}
// Admin Logs
if (_adminManager.HasAdminFlag(player, AdminFlags.Logs))
{
Verb logsVerbEntity = new()
{
Priority = -2,
Text = Loc.GetString("admin-verbs-admin-logs-entity"),
Category = VerbCategory.Admin,
Act = () =>
{
var ui = new AdminLogsEui();
_euiManager.OpenEui(ui, player);
ui.SetLogFilter(search:args.Target.Id.ToString());
},
Impact = LogImpact.Low
};
args.Verbs.Add(logsVerbEntity);
}
// TeleportTo
args.Verbs.Add(new Verb
{
Text = Loc.GetString("admin-verbs-teleport-to"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/open.svg.192dpi.png")),
Act = () =>
{
_console.ExecuteCommand(player, $"tpto {GetNetEntity(args.Target)}");
},
Impact = LogImpact.Low
});
// TeleportHere
args.Verbs.Add(new Verb
{
Text = Loc.GetString("admin-verbs-teleport-here"),
Category = VerbCategory.Admin,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/close.svg.192dpi.png")),
Act = () =>
{
if (HasComp<MapGridComponent>(args.Target))
{
if (player.AttachedEntity != null)
{
var mapPos = _transformSystem.GetMapCoordinates(player.AttachedEntity.Value);
if (TryComp(args.Target, out PhysicsComponent? targetPhysics))
{
var offset = targetPhysics.LocalCenter;
var rotation = _transformSystem.GetWorldRotation(args.Target);
offset = rotation.RotateVec(offset);
mapPos = mapPos.Offset(-offset);
}
_console.ExecuteCommand(player, $"tpgrid {GetNetEntity(args.Target)} {mapPos.X} {mapPos.Y} {mapPos.MapId}");
}
}
else
{
_console.ExecuteCommand(player, $"tpto {args.User} {args.Target}");
}
},
Impact = LogImpact.Low
});
// This logic is needed to be able to modify the AI's laws through its core and eye.
EntityUid? target = null;
SiliconLawBoundComponent? lawBoundComponent = null;
if (TryComp(args.Target, out lawBoundComponent))
{
target = args.Target;
}
// When inspecting the core we can find the entity with its laws by looking at the AiHolderComponent.
else if (TryComp<StationAiHolderComponent>(args.Target, out var holder) && holder.Slot.Item != null
&& TryComp(holder.Slot.Item, out lawBoundComponent))
{
target = holder.Slot.Item.Value;
// For the eye we can find the entity with its laws as the source of the movement relay since the eye
// is just a proxy for it to move around and look around the station.
}
else if (TryComp<MovementRelayTargetComponent>(args.Target, out var relay)
&& TryComp(relay.Source, out lawBoundComponent))
{
target = relay.Source;
}
if (lawBoundComponent != null && target != null && _adminManager.HasAdminFlag(player, AdminFlags.Moderator))
{
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("silicon-law-ui-verb"),
Category = VerbCategory.Admin,
Act = () =>
{
var ui = new SiliconLawEui(_siliconLawSystem, EntityManager, _adminManager);
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
{
return;
}
_euiManager.OpenEui(ui, session);
ui.UpdateLaws(lawBoundComponent, target.Value);
},
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
});
}
}
}
private void AddDebugVerbs(GetVerbsEvent<Verb> args)
{
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;
var player = actor.PlayerSession;
// Delete verb
if (_toolshed.ActivePermissionController?.CheckInvokable(new CommandSpec(_toolshed.DefaultEnvironment.GetCommand("delete"), null), player, out _) ?? false)
{
Verb verb = new()
{
Text = Loc.GetString("delete-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
Act = () => EntityManager.DeleteEntity(args.Target),
Impact = LogImpact.Medium,
ConfirmationPopup = true
};
args.Verbs.Add(verb);
}
// Rejuvenate verb
if (_toolshed.ActivePermissionController?.CheckInvokable(new CommandSpec(_toolshed.DefaultEnvironment.GetCommand("rejuvenate"), null), player, out _) ?? false)
{
Verb verb = new()
{
Text = Loc.GetString("rejuvenate-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/rejuvenate.svg.192dpi.png")),
Act = () => _rejuvenate.PerformRejuvenate(args.Target),
Impact = LogImpact.Medium
};
args.Verbs.Add(verb);
}
// Control mob verb
if (_toolshed.ActivePermissionController?.CheckInvokable(new CommandSpec(_toolshed.DefaultEnvironment.GetCommand("mind"), "control"), player, out _) ?? false &&
args.User != args.Target)
{
Verb verb = new()
{
Text = Loc.GetString("control-mob-verb-get-data-text"),
Category = VerbCategory.Debug,
// TODO VERB ICON control mob icon
Act = () =>
{
_mindSystem.ControlMob(args.User, args.Target);
},
Impact = LogImpact.High,
ConfirmationPopup = true
};
args.Verbs.Add(verb);
}
// Make Sentient verb
if (_groupController.CanCommand(player, "makesentient") &&
args.User != args.Target &&
!EntityManager.HasComponent<MindContainerComponent>(args.Target))
{
Verb verb = new()
{
Text = Loc.GetString("make-sentient-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/sentient.svg.192dpi.png")),
Act = () => MakeSentientCommand.MakeSentient(args.Target, EntityManager),
Impact = LogImpact.Medium
};
args.Verbs.Add(verb);
}
if (TryComp<InventoryComponent>(args.Target, out var inventoryComponent))
{
// Strip all verb
if (_groupController.CanCommand(player, "stripall"))
{
args.Verbs.Add(new Verb
{
Text = Loc.GetString("strip-all-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
Act = () => _console.RemoteExecuteCommand(player, $"stripall \"{args.Target}\""),
Impact = LogImpact.Medium
});
}
// set outfit verb
if (_groupController.CanCommand(player, "setoutfit"))
{
Verb verb = new()
{
Text = Loc.GetString("set-outfit-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
Act = () => _euiManager.OpenEui(new SetOutfitEui(GetNetEntity(args.Target)), player),
Impact = LogImpact.Medium
};
args.Verbs.Add(verb);
}
}
// In range unoccluded verb
if (_groupController.CanCommand(player, "inrangeunoccluded"))
{
Verb verb = new()
{
Text = Loc.GetString("in-range-unoccluded-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/information.svg.192dpi.png")),
Act = () =>
{
var message = _examine.InRangeUnOccluded(args.User, args.Target)
? Loc.GetString("in-range-unoccluded-verb-on-activate-not-occluded")
: Loc.GetString("in-range-unoccluded-verb-on-activate-occluded");
_popup.PopupEntity(message, args.Target, args.User);
}
};
args.Verbs.Add(verb);
}
// Get Disposal tube direction verb
if (_groupController.CanCommand(player, "tubeconnections") &&
EntityManager.TryGetComponent(args.Target, out DisposalTubeComponent? tube))
{
Verb verb = new()
{
Text = Loc.GetString("tube-direction-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/information.svg.192dpi.png")),
Act = () => _disposalTubes.PopupDirections(args.Target, tube, args.User)
};
args.Verbs.Add(verb);
}
// Make ghost role verb
if (_groupController.CanCommand(player, "makeghostrole") &&
!(EntityManager.GetComponentOrNull<MindContainerComponent>(args.Target)?.HasMind ?? false))
{
Verb verb = new();
verb.Text = Loc.GetString("make-ghost-role-verb-get-data-text");
verb.Category = VerbCategory.Debug;
// TODO VERB ICON add ghost icon
// Where is the national park service icon for haunted forests?
verb.Act = () => _ghostRoleSystem.OpenMakeGhostRoleEui(player, args.Target);
verb.Impact = LogImpact.Medium;
args.Verbs.Add(verb);
}
if (_groupController.CanAdminMenu(player) &&
EntityManager.TryGetComponent(args.Target, out ConfigurationComponent? config))
{
Verb verb = new()
{
Text = Loc.GetString("configure-verb-get-data-text"),
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")),
Category = VerbCategory.Debug,
Act = () => _uiSystem.OpenUi(args.Target, ConfigurationUiKey.Key, actor.PlayerSession)
};
args.Verbs.Add(verb);
}
// Add verb to open Solution Editor
if (_groupController.CanCommand(player, "addreagent") &&
EntityManager.HasComponent<SolutionContainerManagerComponent>(args.Target))
{
Verb verb = new()
{
Text = Loc.GetString("edit-solutions-verb-get-data-text"),
Category = VerbCategory.Debug,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/spill.svg.192dpi.png")),
Act = () => OpenEditSolutionsEui(player, args.Target),
Impact = LogImpact.Medium // maybe high depending on WHAT reagents they add...
};
args.Verbs.Add(verb);
}
}
#region SolutionsEui
private void OnSolutionChanged(Entity<SolutionContainerManagerComponent> entity, ref SolutionContainerChangedEvent args)
{
foreach (var list in _openSolutionUis.Values)
{
foreach (var eui in list)
{
if (eui.Target == entity.Owner)
eui.StateDirty();
}
}
}
public void OpenEditSolutionsEui(ICommonSession session, EntityUid uid)
{
if (session.AttachedEntity == null)
return;
var eui = new EditSolutionsEui(uid);
_euiManager.OpenEui(eui, session);
eui.StateDirty();
if (!_openSolutionUis.ContainsKey(session)) {
_openSolutionUis[session] = new List<EditSolutionsEui>();
}
_openSolutionUis[session].Add(eui);
}
public void OnEditSolutionsEuiClosed(ICommonSession session, EditSolutionsEui eui)
{
_openSolutionUis[session].Remove(eui);
if (_openSolutionUis[session].Count == 0)
_openSolutionUis.Remove(session);
}
private void Reset(RoundRestartCleanupEvent ev)
{
foreach (var euis in _openSolutionUis.Values)
{
foreach (var eui in euis.ToList())
{
eui.Close();
}
}
_openSolutionUis.Clear();
}
#endregion
}
}