Files
Delta-v/Content.Server/Administration/Systems/AdminVerbSystem.cs
T
29e55b9464 Upstream Merge (June / July) attempt 2 electric boogaloo (#4607)
* Fix the sensor monitoring console forcing a GC every 3 seconds (#38146)

* Optimize sensor monitoring window graph drawing

* Add shared static Vector2 pool for all GraphView instances

* Address requested changes

* remove lock

* Update submodule to 264.0.0 (#38629)

* Toy/Plushie Inhands and Wearables (#38514)

* Fixed dependency injection and some other issues in a few places.

* More issue fixes

* patchfor broken NetworkConfiguratorLinkMenu (#38632)

fix

* Fix solutions flickering when transferring contents (#34838)

* Use Solution clones when applying SolutionComponent states

* Revert "Use Solution clones when applying SolutionComponent states"

This reverts commit 013fd111cf92b22562e00f98a7aaa49bc4b4ed62.

* Make Solution implement ICloneable and rename Clone method.

* Copy CanReact value when cloning a Solution

* Convert to IRobustCloneable

* Fix typos in guidebook: Buisness → Business (#38636)

* Fix typo in `MinorAntagonists.xml`

Buisness → Business

* Fix typo in `YourFirstCharacter.xml`

Buisness → Business

* Various Headphones Fixes and Tweaks (#38479)

* sprites, wearables

* neck

* icon-on sprite

* Cleanup prototype instantiation in `DamageTest` (#38639)

Cleanup prototype instantiation in DamageTest

* Cleanup prototype instantiation in `ExplosionSystem` (#38642)

Cleanup prototype instantiation in ExplosionSystem

* AddBodyPartCommand localization. (#38612)

commit

* fix ItemSlotsSystem debug assert (#38655)

* Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536)

* Added directional beacons (#38284)

* Added directional beacons

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

* Fixed names

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

---------

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

* Power stat and nuke codes commands get some LEC love. (#38585)

* commit

* requested changes.

* Dsay Dirty and Follow commands converted to LEC and localized. (#38666)

* commit

* whoopwhoopwhoop

* Retro laser sprite fix (#38676)

* Fixed everything except the icon

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

* fixed icon

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

---------

Signed-off-by: Nox38 <nebulousnox38@gmail.com>

* fix water coolers (#38681)

* Monochromacy typo fix (#38686)

* fixes the typo

* Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Validate `CloningSettingsPrototype`s (#38688)

* Validate CloningSettingsPrototypes

* Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Check EventComponents too

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Add test of objective-related console commands (#36400)

* Add test of objective add/list/remove commands

* Not sure why we're validating test prototypes, but sure

* We don't need a map

* Improvements and fixups for New Status Effect API (#38660)

* Predict healing and bloodstream (#38690)

* initial commit

* reapply 38126

* fix rootable

* someone missed an important minus sign here

* try this

* fix

* fix

* reenable crit hits

* cleanup

* fix status time dirtying

* fix

* camelCase

* Healing and bloodstream prediction fixes.

* Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661)

* Resolving Wizard Recall on Nuke disk making it impossible to disarm
- Adding a DisarmBomb case to nuke status update loop
- Changing a few methods and parameters to properly follow formatting standards
- Updating some names to follow camelCase

* Updating missed tag

* Reverting DataField change

Should prevent this preventative bugfix being a breaking change.

* Switch HSV to the default colorspace for character customization (#38434)

* Made HSV default for character editor

* Adds/fixes comments to HSV defaulting

* Added dropbox fix, potentially cursed

* Revert "Added dropbox fix, potentially cursed"

This reverts commit a709883366fbee813e839742125e70844672af29.

---------

Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com>

* Fix: Don't deploy foldables when clicking on items inside containers (#38709)

* Fix

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Pressure Relief Valve (#36708)

* initial system (this math is probably WRONG)

* General code cleanup and OnExamined support
(holy moly this code sucks)

* UICode and related events foundation
TODO:
- Actually write the XAML UI and the underlying system
- Un-shitcode the entire thing
- Actually test everything...

* Working UI code
TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't.

* Remove one TODO for unshitcoding the examine code

* Add reminder
yea

* Make predicted (defenitely isn't)
(also defenitely isn't a copypaste from pressure pump code)

* It's predicted!
TODO:
- Give it snazzy predicted visuals!
- Have a different field for pressure entry, lest it gets bulldozed every UI update.

* Improve gas pressure relief valve UI
TODO: Reminder to reduce amount of dirties using deltafields

* Implement DirtyField prediction

* Entity<T> cleanup
A lot of Entity<T> conversions and lukewarm cleanup.

Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell.

* More cleanup and comments

* Remove TODO comment on bulldozing window title

* """refactoring"""
- Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance.
- More Entity<T> conversions because I like them.
- Move UI creation handling over entirely to the ActivatableUI system.
- Fix a hardcoded locale string (why????).

* Add visuals

* Revert debugging variable replacememt
yea

* Revert skissue

* Remove unused using directives and remove TODO

* Localize, cleanup, document

* Fix adminlogging discrepancy

* Add ability to construct, add guidebook entry

* Clear up comment

* Add guidebook tooltip to valve

* Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor

* Adds more input handling and adds autofill on open

* Un-deepfry input validator shitcode
Genuinely what was I smoking

* improve visuals logic

* Refactor again
- Update math to the correct implementation
- Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs

* I'm sorry but I hate warnings

* Remove unused using directive in AtmosphereSystem.Gases.cs

* Review and cleanup

* Lukewarm UI glossup

* Maintainer for the upstream project btw

* Remove redundant state sets and messy logic

* Unduplicate valve updater code

* Redo UI (im sorry Slarti)

* run tests

* Test refactored UI messaging

* Second round of UI improvements
- God please find a way to improve this system. Feels bad.

* Update loop implementation

* Further predict UI

* Clear up SetToCurrentThreshold

* cleanup

* Update to master + pipe layers and bug fixes
want to run tests

* fixes

* Deploy rename pipebomb

* Documentation and requested changes

* Rename the method that wiggled away

* Undo rounding changes

* Fix comment

* Rename and cleanup

* Apply suggestions from code review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Fix TextLinkTag (#32203)

* Adjust uplink buy button to be under item icon (#38596)

* Adjusted uplink buy button to be under item icon

* Put the discount subtext under the icon

* Indent fixes, added margin

---------

Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com>

* Scurrets - Audio Improvements (#38482)

* Scurret audio tuning

* Add new sfx

* Update sneezing sfx

* YAML support

* Rename a folder

* make telesci wreck easier (#37569)

rel

* Validate `ShaderPrototype` IDs (#38728)

* Convert all shader prototype string literals to protoids in overlays

* Convert more shader prototype literal strings to protoids

* Convert ValidatePrototypeId to ProtoId

* Later

* [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664)

* fixed

* clean up

* orks fix smart

* review fix 1

* more requested changes

* less cursed

* more descriptive description

* better wording

* Tiny Tiny Cleanup of the EyeClosingSystem. (#38734)

Update EyeClosingSystem.cs

* Fix human skin tone distribution (#38701)

* fix: Use PredictedQueueDel for gib spell (#38729)

* fix: don't default to uncharged sprite state for cells (#38730)

* Fix Hristov description - remove inaccurate technical specs (#38746)

- Removes inaccurate 'armor piercing 14.5mm shells' reference
- Replaces it with a more funny description, matching the style of the other snipers and guns
- Keeps ammunition type '.60 anti-materiel ammo' specification
- Fixes issue #38590

Co-authored-by: Arthur Fiorese de Andrade <aandrade@cmcxs.gov.br>

* feat: allow mopping evaporating puddles (#38743)

* Validate remaining `ProtoId` strings (#38747)

Validate remaining ProtoId strings

* Validate `ProtoId`s in tests (#38745)

* Convert string literals to protoids in Content.Tests

* Convert string literals to protoids or consts in Content.IntegrationTests

* Fix linter failures
Tricksy static using misled me

* Cleanup warning in StomachSystem (#38748)

you did not see this

* Vox scars (#38592)

* Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl

* Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl"

This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15.

* locale key fix

* Changed top surgery scar names to be more generalized

* Adjusted face scars

* Formatting fixes

---------

Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com>

* UnlockNode command to LEC. (#38751)

* commit

* Update UnlockNodeCommand.cs

* commit

* move command locale to its own file.

* Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Typofixes for figurine dialogue (#38737)

* Typofixes for figurine dialogue

* Forgot two

* Janitor Tool: Wire Brush (#38667)

* Wow! It's -brush-

* spacing.

* Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* fixed changes

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

* Minor escape menu UX improvements (#38650)

* fix: spellbooks can have infinite charges (#38376)

* fix: spellbooks can have infinite charges

* refactor: indicate infinite spellbook charges with null

Not sure if I like this much better...
2025-11-06 18:22:39 +00:00

674 lines
30 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;
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.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;
using Content.Shared._Impstation.Thaven.Components; // DeltaV
using Content.Server._Impstation.Thaven; // DeltaV
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!;
[Dependency] private readonly ThavenMoodsSystem _moods = default!; // DeltaV
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 (!TryComp(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);
// DeltaV - CuratorHelp
Verb cHelpVerb = new();
cHelpVerb.Text = Loc.GetString("chelp-verb-get-data-text");
cHelpVerb.Category = VerbCategory.Admin;
cHelpVerb.Icon = new SpriteSpecifier.Texture(new("/Textures/_DV/Interface/curator2.svg.192dpi.png"));
cHelpVerb.Act = () =>
_console.RemoteExecuteCommand(player, $"openchelp \"{targetActor.PlayerSession.UserId}\"");
cHelpVerb.Impact = LogImpact.Low;
args.Verbs.Add(cHelpVerb);
// 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"),
});
}
// Begin DeltaV Additions - thaven moods
if (TryComp<ThavenMoodsComponent>(args.Target, out var moods))
{
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("thaven-moods-ui-verb"),
Category = VerbCategory.Admin,
Act = () =>
{
var ui = new ThavenMoodsEui(_moods, EntityManager, _adminManager);
if (!_playerManager.TryGetSessionByEntity(args.User, out var session))
return;
_euiManager.OpenEui(ui, session);
ui.UpdateMoods(moods, args.Target);
},
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
});
}
// End DeltaV Additions
// open camera
args.Verbs.Add(new Verb()
{
Priority = 10,
Text = Loc.GetString("admin-verbs-camera"),
Message = Loc.GetString("admin-verbs-camera-description"),
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/vv.svg.192dpi.png")),
Category = VerbCategory.Admin,
Act = () =>
{
var ui = new AdminCameraEui(args.Target);
_euiManager.OpenEui(ui, player);
},
Impact = LogImpact.Low
});
}
}
private void AddDebugVerbs(GetVerbsEvent<Verb> args)
{
if (!TryComp(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 = () => Del(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 &&
!HasComp<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 = () => _mindSystem.MakeSentient(args.Target),
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") &&
TryComp(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) &&
TryComp(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") &&
HasComp<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
}
}