| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- using System.Linq;
- using Content.Server.Administration;
- using Content.Server.Chat.Managers;
- using Content.Server.Radio.Components;
- using Content.Server.Roles;
- using Content.Server.Station.Systems;
- using Content.Shared.Administration;
- using Content.Shared.Chat;
- using Content.Shared.Emag.Systems;
- using Content.Shared.GameTicking;
- using Content.Shared.Mind;
- using Content.Shared.Mind.Components;
- using Content.Shared.Roles;
- using Content.Shared.Silicons.Laws;
- using Content.Shared.Silicons.Laws.Components;
- using Content.Shared.Wires;
- using Robust.Server.GameObjects;
- using Robust.Shared.Audio;
- using Robust.Shared.Containers;
- using Robust.Shared.Player;
- using Robust.Shared.Prototypes;
- using Robust.Shared.Toolshed;
- namespace Content.Server.Silicons.Laws;
- /// <inheritdoc/>
- public sealed class SiliconLawSystem : SharedSiliconLawSystem
- {
- [Dependency] private readonly IChatManager _chatManager = default!;
- [Dependency] private readonly SharedMindSystem _mind = default!;
- [Dependency] private readonly IPrototypeManager _prototype = default!;
- [Dependency] private readonly SharedRoleSystem _roles = default!;
- [Dependency] private readonly StationSystem _station = default!;
- [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
- [Dependency] private readonly EmagSystem _emag = default!;
- /// <inheritdoc/>
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent<SiliconLawBoundComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<SiliconLawBoundComponent, MindAddedMessage>(OnMindAdded);
- SubscribeLocalEvent<SiliconLawBoundComponent, ToggleLawsScreenEvent>(OnToggleLawsScreen);
- SubscribeLocalEvent<SiliconLawBoundComponent, BoundUIOpenedEvent>(OnBoundUIOpened);
- SubscribeLocalEvent<SiliconLawBoundComponent, PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
- SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws);
- SubscribeLocalEvent<SiliconLawProviderComponent, IonStormLawsEvent>(OnIonStormLaws);
- SubscribeLocalEvent<SiliconLawProviderComponent, MindAddedMessage>(OnLawProviderMindAdded);
- SubscribeLocalEvent<SiliconLawProviderComponent, MindRemovedMessage>(OnLawProviderMindRemoved);
- SubscribeLocalEvent<SiliconLawProviderComponent, SiliconEmaggedEvent>(OnEmagLawsAdded);
- }
- private void OnMapInit(EntityUid uid, SiliconLawBoundComponent component, MapInitEvent args)
- {
- GetLaws(uid, component);
- }
- private void OnMindAdded(EntityUid uid, SiliconLawBoundComponent component, MindAddedMessage args)
- {
- if (!TryComp<ActorComponent>(uid, out var actor))
- return;
- var msg = Loc.GetString("laws-notify");
- var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
- _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.FromHex("#5ed7aa"));
- if (!TryComp<SiliconLawProviderComponent>(uid, out var lawcomp))
- return;
- if (!lawcomp.Subverted)
- return;
- var modifedLawMsg = Loc.GetString("laws-notify-subverted");
- var modifiedLawWrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", modifedLawMsg));
- _chatManager.ChatMessageToOne(ChatChannel.Server, modifedLawMsg, modifiedLawWrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red);
- }
- private void OnLawProviderMindAdded(Entity<SiliconLawProviderComponent> ent, ref MindAddedMessage args)
- {
- if (!ent.Comp.Subverted)
- return;
- EnsureSubvertedSiliconRole(args.Mind);
- }
- private void OnLawProviderMindRemoved(Entity<SiliconLawProviderComponent> ent, ref MindRemovedMessage args)
- {
- if (!ent.Comp.Subverted)
- return;
- RemoveSubvertedSiliconRole(args.Mind);
- }
- private void OnToggleLawsScreen(EntityUid uid, SiliconLawBoundComponent component, ToggleLawsScreenEvent args)
- {
- if (args.Handled || !TryComp<ActorComponent>(uid, out var actor))
- return;
- args.Handled = true;
- _userInterface.TryToggleUi(uid, SiliconLawsUiKey.Key, actor.PlayerSession);
- }
- private void OnBoundUIOpened(EntityUid uid, SiliconLawBoundComponent component, BoundUIOpenedEvent args)
- {
- TryComp(uid, out IntrinsicRadioTransmitterComponent? intrinsicRadio);
- var radioChannels = intrinsicRadio?.Channels;
- var state = new SiliconLawBuiState(GetLaws(uid).Laws, radioChannels);
- _userInterface.SetUiState(args.Entity, SiliconLawsUiKey.Key, state);
- }
- private void OnPlayerSpawnComplete(EntityUid uid, SiliconLawBoundComponent component, PlayerSpawnCompleteEvent args)
- {
- component.LastLawProvider = args.Station;
- }
- private void OnDirectedGetLaws(EntityUid uid, SiliconLawProviderComponent component, ref GetSiliconLawsEvent args)
- {
- if (args.Handled)
- return;
- if (component.Lawset == null)
- component.Lawset = GetLawset(component.Laws);
- args.Laws = component.Lawset;
- args.Handled = true;
- }
- private void OnIonStormLaws(EntityUid uid, SiliconLawProviderComponent component, ref IonStormLawsEvent args)
- {
- // Emagged borgs are immune to ion storm
- if (!_emag.CheckFlag(uid, EmagType.Interaction))
- {
- component.Lawset = args.Lawset;
- // gotta tell player to check their laws
- NotifyLawsChanged(uid, component.LawUploadSound);
- // Show the silicon has been subverted.
- component.Subverted = true;
- // new laws may allow antagonist behaviour so make it clear for admins
- if(_mind.TryGetMind(uid, out var mindId, out _))
- EnsureSubvertedSiliconRole(mindId);
- }
- }
- private void OnEmagLawsAdded(EntityUid uid, SiliconLawProviderComponent component, ref SiliconEmaggedEvent args)
- {
- if (component.Lawset == null)
- component.Lawset = GetLawset(component.Laws);
- // Show the silicon has been subverted.
- component.Subverted = true;
- // Add the first emag law before the others
- component.Lawset?.Laws.Insert(0, new SiliconLaw
- {
- LawString = Loc.GetString("law-emag-custom", ("name", Name(args.user)), ("title", Loc.GetString(component.Lawset.ObeysTo))),
- Order = 0
- });
- //Add the secrecy law after the others
- component.Lawset?.Laws.Add(new SiliconLaw
- {
- LawString = Loc.GetString("law-emag-secrecy", ("faction", Loc.GetString(component.Lawset.ObeysTo))),
- Order = component.Lawset.Laws.Max(law => law.Order) + 1
- });
- }
- protected override void EnsureSubvertedSiliconRole(EntityUid mindId)
- {
- base.EnsureSubvertedSiliconRole(mindId);
- if (!_roles.MindHasRole<SubvertedSiliconRoleComponent>(mindId))
- _roles.MindAddRole(mindId, "MindRoleSubvertedSilicon", silent: true);
- }
- protected override void RemoveSubvertedSiliconRole(EntityUid mindId)
- {
- base.RemoveSubvertedSiliconRole(mindId);
- if (_roles.MindHasRole<SubvertedSiliconRoleComponent>(mindId))
- _roles.MindTryRemoveRole<SubvertedSiliconRoleComponent>(mindId);
- }
- public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return new SiliconLawset();
- var ev = new GetSiliconLawsEvent(uid);
- RaiseLocalEvent(uid, ref ev);
- if (ev.Handled)
- {
- component.LastLawProvider = uid;
- return ev.Laws;
- }
- var xform = Transform(uid);
- if (_station.GetOwningStation(uid, xform) is { } station)
- {
- RaiseLocalEvent(station, ref ev);
- if (ev.Handled)
- {
- component.LastLawProvider = station;
- return ev.Laws;
- }
- }
- if (xform.GridUid is { } grid)
- {
- RaiseLocalEvent(grid, ref ev);
- if (ev.Handled)
- {
- component.LastLawProvider = grid;
- return ev.Laws;
- }
- }
- if (component.LastLawProvider == null ||
- Deleted(component.LastLawProvider) ||
- Terminating(component.LastLawProvider.Value))
- {
- component.LastLawProvider = null;
- }
- else
- {
- RaiseLocalEvent(component.LastLawProvider.Value, ref ev);
- if (ev.Handled)
- {
- return ev.Laws;
- }
- }
- RaiseLocalEvent(ref ev);
- return ev.Laws;
- }
- public override void NotifyLawsChanged(EntityUid uid, SoundSpecifier? cue = null)
- {
- base.NotifyLawsChanged(uid, cue);
- if (!TryComp<ActorComponent>(uid, out var actor))
- return;
- var msg = Loc.GetString("laws-update-notify");
- var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg));
- _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.Channel, colorOverride: Color.Red);
- if (cue != null && _mind.TryGetMind(uid, out var mindId, out _))
- _roles.MindPlaySound(mindId, cue);
- }
- /// <summary>
- /// Extract all the laws from a lawset's prototype ids.
- /// </summary>
- public SiliconLawset GetLawset(ProtoId<SiliconLawsetPrototype> lawset)
- {
- var proto = _prototype.Index(lawset);
- var laws = new SiliconLawset()
- {
- Laws = new List<SiliconLaw>(proto.Laws.Count)
- };
- foreach (var law in proto.Laws)
- {
- laws.Laws.Add(_prototype.Index<SiliconLawPrototype>(law));
- }
- laws.ObeysTo = proto.ObeysTo;
- return laws;
- }
- /// <summary>
- /// Set the laws of a silicon entity while notifying the player.
- /// </summary>
- public void SetLaws(List<SiliconLaw> newLaws, EntityUid target, SoundSpecifier? cue = null)
- {
- if (!TryComp<SiliconLawProviderComponent>(target, out var component))
- return;
- if (component.Lawset == null)
- component.Lawset = new SiliconLawset();
- component.Lawset.Laws = newLaws;
- NotifyLawsChanged(target, cue);
- }
- protected override void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
- {
- // TODO: Prediction dump this
- if (!TryComp(args.Entity, out SiliconLawProviderComponent? provider))
- return;
- var lawset = GetLawset(provider.Laws).Laws;
- var query = EntityManager.CompRegistryQueryEnumerator(ent.Comp.Components);
- while (query.MoveNext(out var update))
- {
- SetLaws(lawset, update, provider.LawUploadSound);
- }
- }
- }
- [ToolshedCommand, AdminCommand(AdminFlags.Admin)]
- public sealed class LawsCommand : ToolshedCommand
- {
- private SiliconLawSystem? _law;
- [CommandImplementation("list")]
- public IEnumerable<EntityUid> List()
- {
- var query = EntityManager.EntityQueryEnumerator<SiliconLawBoundComponent>();
- while (query.MoveNext(out var uid, out _))
- {
- yield return uid;
- }
- }
- [CommandImplementation("get")]
- public IEnumerable<string> Get([PipedArgument] EntityUid lawbound)
- {
- _law ??= GetSys<SiliconLawSystem>();
- foreach (var law in _law.GetLaws(lawbound).Laws)
- {
- yield return $"law {law.LawIdentifierOverride ?? law.Order.ToString()}: {Loc.GetString(law.LawString)}";
- }
- }
- }
|