From 7ddee71379bd93a540a6f2b4c49821f905661449 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 14 Aug 2023 19:34:23 -0400 Subject: [PATCH] More borg tweaks (#19143) * borg tweaks but i'm gonna go code fun stuff first * werkin' on it * a ton of tweaks * fuck everyone and then myself --- .../Behaviors/EmptyContainersBehaviour.cs | 10 +--- Content.Server/Flash/FlashSystem.cs | 2 +- .../ToggleableGhostRoleComponent.cs | 2 +- .../Ghost/Roles/ToggleableGhostRoleSystem.cs | 12 ++-- .../Mind/Components/MindContainerComponent.cs | 6 ++ Content.Server/Mind/MindSystem.cs | 22 +++++-- Content.Server/Roles/SubvertedSiliconRole.cs | 8 +++ .../Silicons/Borgs/BorgSystem.MMI.cs | 1 + Content.Server/Silicons/Borgs/BorgSystem.cs | 30 ++++------ .../Silicons/Laws/SiliconLawSystem.cs | 57 +++++++++++++++++-- Content.Server/Wires/WiresSystem.cs | 6 +- .../Access/Components/AccessComponent.cs | 14 ++++- .../Access/Systems/AccessReaderSystem.cs | 21 +++---- .../Access/Systems/SharedAccessSystem.cs | 46 ++++++--------- .../SharedInteractionSystem.Blocking.cs | 4 ++ .../NameIdentifier/NameIdentifierComponent.cs | 3 + Content.Shared/PAI/PAIComponent.cs | 2 +- Content.Shared/PDA/SharedPdaSystem.cs | 9 ++- .../Borgs/Components/BorgChassisComponent.cs | 39 +------------ .../Silicons/Borgs/Components/MMIComponent.cs | 9 +++ .../Borgs/Components/MMILinkedComponent.cs | 5 +- .../Silicons/Borgs/SharedBorgSystem.cs | 12 +--- .../Components/EmagSiliconLawComponent.cs | 23 +++++++- .../Components/SiliconLawBoundComponent.cs | 10 +++- .../Components/SiliconLawProviderComponent.cs | 2 +- .../Silicons/Laws/SharedSiliconLawSystem.cs | 12 ++++ Content.Shared/Stacks/SharedStackSystem.cs | 3 +- Content.Shared/Stacks/StackComponent.cs | 9 ++- Resources/Locale/en-US/job/job-names.ftl | 1 + .../Locale/en-US/prototypes/roles/antags.ftl | 3 + Resources/Locale/en-US/station-laws/laws.ftl | 1 + .../Mobs/Cyborgs/base_borg_chassis.yml | 27 +++++++-- .../Entities/Mobs/Cyborgs/borg_chassis.yml | 12 ++-- .../Prototypes/Entities/Mobs/Player/base.yml | 3 +- .../Entities/Mobs/Player/silicon.yml | 27 +++++++-- .../Prototypes/Entities/Objects/Fun/pai.yml | 4 ++ .../Specific/Robotics/endoskeleton.yml | 5 -- .../Objects/Specific/Robotics/mmi.yml | 4 +- Resources/Prototypes/Roles/Antags/silicon.yml | 6 ++ .../Prototypes/Roles/Jobs/departments.yml | 2 +- 40 files changed, 299 insertions(+), 175 deletions(-) create mode 100644 Content.Server/Roles/SubvertedSiliconRole.cs create mode 100644 Resources/Prototypes/Roles/Antags/silicon.yml diff --git a/Content.Server/Destructible/Thresholds/Behaviors/EmptyContainersBehaviour.cs b/Content.Server/Destructible/Thresholds/Behaviors/EmptyContainersBehaviour.cs index abd5c531a6..253fd19a7f 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/EmptyContainersBehaviour.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/EmptyContainersBehaviour.cs @@ -1,4 +1,3 @@ -using Content.Shared.Random.Helpers; using Robust.Server.Containers; using Robust.Shared.Containers; @@ -13,9 +12,6 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataField("containers")] public List Containers = new(); - [DataField("randomOffset")] - public float RandomOffset = 0.25f; - public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) { if (!system.EntityManager.TryGetComponent(owner, out var containerManager)) @@ -29,11 +25,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors if (!containerSys.TryGetContainer(owner, containerId, out var container, containerManager)) continue; - var entities = containerSys.EmptyContainer(container, true); - foreach (var ent in entities) - { - ent.RandomOffset(RandomOffset); - } + containerSys.EmptyContainer(container, true); } } } diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index 6cab18daf3..04b3f0cd24 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Popups; using Content.Server.Stunnable; using Content.Shared.Charges.Components; using Content.Shared.Charges.Systems; +using Content.Shared.Damage; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Flash; using Content.Shared.IdentityManagement; @@ -43,7 +44,6 @@ namespace Content.Server.Flash SubscribeLocalEvent(OnFlashMeleeHit); // ran before toggling light for extra-bright lantern SubscribeLocalEvent(OnFlashUseInHand, before: new []{ typeof(HandheldLightSystem) }); - SubscribeLocalEvent(OnInventoryFlashAttempt); SubscribeLocalEvent(OnFlashImmunityFlashAttempt); diff --git a/Content.Server/Ghost/Roles/Components/ToggleableGhostRoleComponent.cs b/Content.Server/Ghost/Roles/Components/ToggleableGhostRoleComponent.cs index e00587d069..8af0886d92 100644 --- a/Content.Server/Ghost/Roles/Components/ToggleableGhostRoleComponent.cs +++ b/Content.Server/Ghost/Roles/Components/ToggleableGhostRoleComponent.cs @@ -3,7 +3,7 @@ /// /// This is used for a ghost role which can be toggled on and off at will, like a PAI. /// -[RegisterComponent] +[RegisterComponent, Access(typeof(ToggleableGhostRoleSystem))] public sealed class ToggleableGhostRoleComponent : Component { [DataField("examineTextMindPresent")] diff --git a/Content.Server/Ghost/Roles/ToggleableGhostRoleSystem.cs b/Content.Server/Ghost/Roles/ToggleableGhostRoleSystem.cs index e2fef7d90b..3655da6fd8 100644 --- a/Content.Server/Ghost/Roles/ToggleableGhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/ToggleableGhostRoleSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Ghost.Roles.Components; +using Content.Server.Mind; using Content.Server.Mind.Components; using Content.Server.PAI; using Content.Shared.Examine; @@ -16,6 +17,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem { [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly MindSystem _mind = default!; //todo this really shouldn't be in here but this system was converted from PAIs [Dependency] private readonly PAISystem _pai = default!; @@ -79,7 +81,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem private void OnMindAdded(EntityUid uid, ToggleableGhostRoleComponent pai, MindAddedMessage args) { // Mind was added, shutdown the ghost role stuff so it won't get in the way - RemComp(uid); + RemCompDeferred(uid); UpdateAppearance(uid, ToggleableGhostRoleStatus.On); } @@ -105,12 +107,12 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem Text = Loc.GetString(component.WipeVerbText), Act = () => { - if (component.Deleted || !HasComp(uid)) + if (!TryComp(uid, out var mindComp) || mindComp.Mind == null) return; // Wiping device :( // The shutdown of the Mind should cause automatic reset of the pAI during OnMindRemoved // EDIT: But it doesn't!!!! Wtf? Do stuff manually - RemComp(uid); + _mind.TransferTo(mindComp.Mind, null); _popup.PopupEntity(Loc.GetString(component.WipeVerbPopup), uid, args.User, PopupType.Large); UpdateAppearance(uid, ToggleableGhostRoleStatus.Off); _pai.PAITurningOff(uid); @@ -127,8 +129,8 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem { if (component.Deleted || !HasComp(uid)) return; - RemComp(uid); - RemComp(uid); + RemCompDeferred(uid); + RemCompDeferred(uid); _popup.PopupEntity(Loc.GetString(component.StopSearchVerbPopup), uid, args.User); UpdateAppearance(uid, ToggleableGhostRoleStatus.Off); _pai.PAITurningOff(uid); diff --git a/Content.Server/Mind/Components/MindContainerComponent.cs b/Content.Server/Mind/Components/MindContainerComponent.cs index 0333c75ada..4ff36b60f2 100644 --- a/Content.Server/Mind/Components/MindContainerComponent.cs +++ b/Content.Server/Mind/Components/MindContainerComponent.cs @@ -40,6 +40,12 @@ namespace Content.Server.Mind.Components public sealed class MindRemovedMessage : EntityEventArgs { + public Mind OldMind; + + public MindRemovedMessage(Mind oldMind) + { + OldMind = oldMind; + } } public sealed class MindAddedMessage : EntityEventArgs diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index d10511ccf6..fed78f8ad7 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -30,6 +30,7 @@ public sealed class MindSystem : EntitySystem [Dependency] private readonly ActorSystem _actor = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly GhostSystem _ghostSystem = default!; + [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; @@ -125,11 +126,12 @@ public sealed class MindSystem : EntitySystem /// private void InternalEjectMind(EntityUid uid, MindContainerComponent? mind = null) { - if (!Resolve(uid, ref mind, false)) + if (!Resolve(uid, ref mind, false) || mind.Mind == null) return; + var oldMind = mind.Mind; mind.Mind = null; - RaiseLocalEvent(uid, new MindRemovedMessage(), true); + RaiseLocalEvent(uid, new MindRemovedMessage(oldMind), true); } private void OnVisitingTerminating(EntityUid uid, VisitingMindComponent component, ref EntityTerminatingEvent args) @@ -159,7 +161,7 @@ public sealed class MindSystem : EntitySystem return; } - TransferTo(mind, null); + TransferTo(mind, null, createGhost: false); if (component.GhostOnShutdown && mind.Session != null) { @@ -184,7 +186,7 @@ public sealed class MindSystem : EntitySystem { // This should be an error, if it didn't cause tests to start erroring when they delete a player. Log.Warning($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, and no applicable spawn location is available."); - TransferTo(mind, null); + TransferTo(mind, null, createGhost: false); return; } @@ -381,7 +383,7 @@ public sealed class MindSystem : EntitySystem /// /// Thrown if is already owned by another mind. /// - public void TransferTo(Mind mind, EntityUid? entity, bool ghostCheckOverride = false) + public void TransferTo(Mind mind, EntityUid? entity, bool ghostCheckOverride = false, bool createGhost = true) { if (entity == mind.OwnedEntity) return; @@ -407,6 +409,16 @@ public sealed class MindSystem : EntitySystem alreadyAttached = true; } } + else if (createGhost) + { + var position = Deleted(mind.OwnedEntity) + ? _gameTicker.GetObserverSpawnPoint().ToMap(EntityManager, _transform) + : Transform(mind.OwnedEntity.Value).MapPosition; + + entity = Spawn("MobObserver", position); + var ghostComponent = Comp(entity.Value); + _ghostSystem.SetCanReturnToBody(ghostComponent, false); + } var oldComp = mind.OwnedComponent; var oldEntity = mind.OwnedEntity; diff --git a/Content.Server/Roles/SubvertedSiliconRole.cs b/Content.Server/Roles/SubvertedSiliconRole.cs new file mode 100644 index 0000000000..1da518d021 --- /dev/null +++ b/Content.Server/Roles/SubvertedSiliconRole.cs @@ -0,0 +1,8 @@ +using Content.Shared.Roles; + +namespace Content.Server.Roles; + +public sealed class SubvertedSiliconRole : AntagonistRole +{ + public SubvertedSiliconRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind, antagPrototype) { } +} diff --git a/Content.Server/Silicons/Borgs/BorgSystem.MMI.cs b/Content.Server/Silicons/Borgs/BorgSystem.MMI.cs index 34e00001b9..6e70052060 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.MMI.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.MMI.cs @@ -38,6 +38,7 @@ public sealed partial class BorgSystem var ent = args.Entity; var linked = EnsureComp(ent); linked.LinkedMMI = uid; + Dirty(uid, component); if (_mind.TryGetMind(ent, out var mind)) _mind.TransferTo(mind, uid, true); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index afae963862..9b9284c2a9 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Mind; using Content.Server.Mind.Components; using Content.Server.PowerCell; using Content.Server.UserInterface; +using Content.Shared.Access.Systems; using Content.Shared.Alert; using Content.Shared.Database; using Content.Shared.IdentityManagement; @@ -13,6 +14,7 @@ using Content.Shared.Interaction; using Content.Shared.Movement.Systems; using Content.Shared.PowerCell; using Content.Shared.PowerCell.Components; +using Content.Shared.Roles; using Content.Shared.Silicons.Borgs; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Throwing; @@ -30,6 +32,7 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly IBanManager _banManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAccessSystem _access = default!; [Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -41,6 +44,9 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; + [ValidatePrototypeId] + public const string BorgJobId = "Borg"; + /// public override void Initialize() { @@ -66,18 +72,6 @@ public sealed partial class BorgSystem : SharedBorgSystem { UpdateBatteryAlert(uid); _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); - - var coordinates = Transform(uid).Coordinates; - - if (component.StartingBrain != null) - { - component.BrainContainer.Insert(Spawn(component.StartingBrain, coordinates), EntityManager); - } - - foreach (var startingModule in component.StartingModules) - { - component.ModuleContainer.Insert(Spawn(startingModule, coordinates), EntityManager); - } } private void OnChassisInteractUsing(EntityUid uid, BorgChassisComponent component, AfterInteractUsingEvent args) @@ -104,7 +98,7 @@ public sealed partial class BorgSystem : SharedBorgSystem { if (_mind.TryGetMind(used, out var mind) && mind.Session != null) { - if (!CanPlayerBeBorgged(mind.Session, component)) + if (!CanPlayerBeBorgged(mind.Session)) { Popup.PopupEntity(Loc.GetString("borg-player-not-allowed"), used, args.User); return; @@ -218,7 +212,7 @@ public sealed partial class BorgSystem : SharedBorgSystem if (!_mind.TryGetMind(uid, out var mind) || mind.Session == null) return; - if (!CanPlayerBeBorgged(mind.Session, chassisComponent)) + if (!CanPlayerBeBorgged(mind.Session)) { Popup.PopupEntity(Loc.GetString("borg-player-not-allowed-eject"), uid); Container.RemoveEntity(containerEnt, uid); @@ -284,9 +278,9 @@ public sealed partial class BorgSystem : SharedBorgSystem /// public void BorgActivate(EntityUid uid, BorgChassisComponent component) { - component.HasPlayer = true; Popup.PopupEntity(Loc.GetString("borg-mind-added", ("name", Identity.Name(uid, EntityManager))), uid); _powerCell.SetPowerCellDrawEnabled(uid, true); + _access.SetAccessEnabled(uid, true); _appearance.SetData(uid, BorgVisuals.HasPlayer, true); Dirty(uid, component); } @@ -296,9 +290,9 @@ public sealed partial class BorgSystem : SharedBorgSystem /// public void BorgDeactivate(EntityUid uid, BorgChassisComponent component) { - component.HasPlayer = false; Popup.PopupEntity(Loc.GetString("borg-mind-removed", ("name", Identity.Name(uid, EntityManager))), uid); _powerCell.SetPowerCellDrawEnabled(uid, false); + _access.SetAccessEnabled(uid, false); _appearance.SetData(uid, BorgVisuals.HasPlayer, false); Dirty(uid, component); } @@ -307,9 +301,9 @@ public sealed partial class BorgSystem : SharedBorgSystem /// Checks that a player has fulfilled the requirements for the borg job. /// If they don't have enough hours, they cannot be placed into a chassis. /// - public bool CanPlayerBeBorgged(IPlayerSession session, BorgChassisComponent component) + public bool CanPlayerBeBorgged(IPlayerSession session) { - if (_banManager.GetJobBans(session.UserId)?.Contains(component.BorgJobId) == true) + if (_banManager.GetJobBans(session.UserId)?.Contains(BorgJobId) == true) return false; return true; diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 2862e5c1f5..cda9b2d1d9 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -1,7 +1,10 @@ -using Content.Server.Administration; +using System.Linq; +using Content.Server.Administration; using Content.Server.Chat.Managers; using Content.Server.GameTicking; +using Content.Server.Mind; using Content.Server.Mind.Components; +using Content.Server.Roles; using Content.Server.Station.Systems; using Content.Shared.Actions; using Content.Shared.Actions.ActionTypes; @@ -10,8 +13,10 @@ using Content.Shared.Chat; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; using Content.Shared.Examine; +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.Server.Player; using Robust.Shared.Prototypes; @@ -24,6 +29,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem { [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly UserInterfaceSystem _userInterface = default!; @@ -35,6 +41,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnComponentShutdown); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnToggleLawsScreen); SubscribeLocalEvent(OnBoundUIOpened); @@ -42,8 +49,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnDirectedGetLaws); SubscribeLocalEvent(OnDirectedEmagGetLaws); + SubscribeLocalEvent(OnEmagMindAdded); + SubscribeLocalEvent(OnEmagMindRemoved); SubscribeLocalEvent(OnExamined); } + private void OnComponentStartup(EntityUid uid, SiliconLawBoundComponent component, ComponentStartup args) { component.ProvidedAction = new (_prototype.Index(component.ViewLawsAction)); @@ -56,6 +66,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _actions.RemoveAction(uid, component.ProvidedAction); } + private void OnMapInit(EntityUid uid, SiliconLawBoundComponent component, MapInitEvent args) + { + GetLaws(uid, component); + } + private void OnMindAdded(EntityUid uid, SiliconLawBoundComponent component, MindAddedMessage args) { if (!TryComp(uid, out var actor)) @@ -117,13 +132,47 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem if (!args.IsInDetailsRange || !HasComp(uid)) return; + if (component.RequireOpenPanel && TryComp(uid, out var panel) && !panel.Open) + return; + args.PushMarkup(Loc.GetString("laws-compromised-examine")); } protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args) { + if (component.RequireOpenPanel && TryComp(uid, out var panel) && !panel.Open) + return; + base.OnGotEmagged(uid, component, ref args); NotifyLawsChanged(uid); + EnsureEmaggedRole(uid, component); + } + + private void OnEmagMindAdded(EntityUid uid, EmagSiliconLawComponent component, MindAddedMessage args) + { + if (HasComp(uid)) + EnsureEmaggedRole(uid, component); + } + + private void OnEmagMindRemoved(EntityUid uid, EmagSiliconLawComponent component, MindRemovedMessage args) + { + if (component.AntagonistRole == null) + return; + + if (args.OldMind.Roles.FirstOrDefault(r => r is SubvertedSiliconRole) is not { } role) + return; + + _mind.RemoveRole(args.OldMind, role); + } + + private void EnsureEmaggedRole(EntityUid uid, EmagSiliconLawComponent component) + { + if (component.AntagonistRole == null || !_mind.TryGetMind(uid, out var mind)) + return; + + if (_mind.HasRole(mind)) + return; + _mind.AddRole(mind, new SubvertedSiliconRole(mind, _prototype.Index(component.AntagonistRole))); } public List GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) @@ -131,8 +180,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem if (!Resolve(uid, ref component)) return new List(); - var xform = Transform(uid); - var ev = new GetSiliconLawsEvent(uid); RaiseLocalEvent(uid, ref ev); @@ -142,6 +189,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem return ev.Laws; } + var xform = Transform(uid); + if (_station.GetOwningStation(uid, xform) is { } station) { RaiseLocalEvent(station, ref ev); @@ -188,7 +237,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem 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.ConnectedClient, colorOverride: Color.FromHex("#2ed2fd")); + _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.ConnectedClient, colorOverride: Color.Red); } } diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index f3f2ef4c6c..67924ec5e2 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -24,6 +24,7 @@ public sealed class WiresSystem : SharedWiresSystem { [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly ActivatableUISystem _activatableUI = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; @@ -511,10 +512,7 @@ public sealed class WiresSystem : SharedWiresSystem if (args.Open == component.RequireOpen) return; - if (!TryComp(uid, out var ui) || ui.Key == null) - return; - - _uiSystem.TryCloseAll(uid, ui.Key); + _activatableUI.CloseAll(uid); } private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args) diff --git a/Content.Shared/Access/Components/AccessComponent.cs b/Content.Shared/Access/Components/AccessComponent.cs index f6e124c87d..35521d23db 100644 --- a/Content.Shared/Access/Components/AccessComponent.cs +++ b/Content.Shared/Access/Components/AccessComponent.cs @@ -10,17 +10,27 @@ namespace Content.Shared.Access.Components /// [RegisterComponent, NetworkedComponent] [Access(typeof(SharedAccessSystem))] - public sealed class AccessComponent : Component + [AutoGenerateComponentState] + public sealed partial class AccessComponent : Component { + /// + /// True if the access provider is enabled and can grant access. + /// + [DataField("enabled"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public bool Enabled = true; + [DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] [Access(typeof(SharedAccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends + [AutoNetworkedField(true)] public HashSet Tags = new(); /// /// Access Groups. These are added to the tags during map init. After map init this will have no effect. /// [DataField("groups", readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] - public readonly HashSet Groups = new(); + [AutoNetworkedField(true)] + public HashSet Groups = new(); } /// diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index d3c9615af1..96cd3b1d8c 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -8,9 +8,9 @@ using Content.Shared.PDA; using Content.Shared.StationRecords; using Robust.Shared.Containers; using Robust.Shared.GameStates; -using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Robust.Shared.Collections; using Robust.Shared.Prototypes; namespace Content.Shared.Access.Systems; @@ -69,6 +69,8 @@ public sealed class AccessReaderSystem : EntitySystem /// required entity. /// /// The entity to search for a container + /// + /// private bool FindAccessReadersInContainer(EntityUid target, AccessReaderComponent accessReader, out List result) { result = new(); @@ -171,6 +173,11 @@ public sealed class AccessReaderSystem : EntitySystem { FindAccessItemsInventory(uid, out var items); + foreach (var item in new ValueList(items)) + { + items.UnionWith(FindPotentialAccessItems(item)); + } + var ev = new GetAdditionalAccessEvent { Entities = items @@ -204,6 +211,7 @@ public sealed class AccessReaderSystem : EntitySystem /// Finds the access tags on the given entity /// /// The entity that is being searched. + /// /// All of the items to search for access. If none are passed in, will be used. public bool FindStationRecordKeys(EntityUid uid, out ICollection recordKeys, HashSet? items = null) { @@ -277,17 +285,6 @@ public sealed class AccessReaderSystem : EntitySystem private bool FindAccessTagsItem(EntityUid uid, out HashSet tags) { tags = new(); - if (TryComp(uid, out AccessComponent? access)) - { - tags.UnionWith(access.Tags); - } - - if (TryComp(uid, out PdaComponent? pda) && - pda.ContainedId is { Valid: true } id) - { - tags.UnionWith(EntityManager.GetComponent(id).Tags); - } - var ev = new GetAccessTagsEvent(tags, _prototype); RaiseLocalEvent(uid, ref ev); diff --git a/Content.Shared/Access/Systems/SharedAccessSystem.cs b/Content.Shared/Access/Systems/SharedAccessSystem.cs index 85b1cbe37c..eaacaf277b 100644 --- a/Content.Shared/Access/Systems/SharedAccessSystem.cs +++ b/Content.Shared/Access/Systems/SharedAccessSystem.cs @@ -15,28 +15,7 @@ namespace Content.Shared.Access.Systems base.Initialize(); SubscribeLocalEvent(OnAccessInit); - SubscribeLocalEvent(OnAccessGetState); - SubscribeLocalEvent(OnAccessHandleState); - } - - private void OnAccessHandleState(EntityUid uid, AccessComponent component, ref ComponentHandleState args) - { - if (args.Current is not AccessComponentState state) return; - - // Don't do = because prediction and refs - component.Tags.Clear(); - component.Groups.Clear(); - component.Tags.UnionWith(state.Tags); - component.Groups.UnionWith(state.Groups); - } - - private void OnAccessGetState(EntityUid uid, AccessComponent component, ref ComponentGetState args) - { - args.State = new AccessComponentState() - { - Tags = component.Tags, - Groups = component.Groups, - }; + SubscribeLocalEvent(OnGetAccessTags); } private void OnAccessInit(EntityUid uid, AccessComponent component, MapInitEvent args) @@ -52,6 +31,22 @@ namespace Content.Shared.Access.Systems } } + private void OnGetAccessTags(EntityUid uid, AccessComponent component, ref GetAccessTagsEvent args) + { + if (!component.Enabled) + return; + + args.Tags.UnionWith(component.Tags); + } + + public void SetAccessEnabled(EntityUid uid, bool val, AccessComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return; + component.Enabled = val; + Dirty(uid, component); + } + /// /// Replaces the set of access tags we have with the provided set. /// @@ -122,12 +117,5 @@ namespace Content.Shared.Access.Systems TryAddGroups(uid, prototype.ExtendedAccessGroups, access); } } - - [Serializable, NetSerializable] - private sealed class AccessComponentState : ComponentState - { - public HashSet Tags = new(); - public HashSet Groups = new(); - } } } diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs index e5313b5430..9a84789adf 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs @@ -6,6 +6,10 @@ using Content.Shared.Movement.Events; namespace Content.Shared.Interaction; +/// +/// Handles , which prevents various +/// kinds of movement and interactions when attached to an entity. +/// public partial class SharedInteractionSystem { public void InitializeBlocking() diff --git a/Content.Shared/NameIdentifier/NameIdentifierComponent.cs b/Content.Shared/NameIdentifier/NameIdentifierComponent.cs index 0fcb3330f7..49be08a6a3 100644 --- a/Content.Shared/NameIdentifier/NameIdentifierComponent.cs +++ b/Content.Shared/NameIdentifier/NameIdentifierComponent.cs @@ -3,6 +3,9 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy namespace Content.Shared.NameIdentifier; +/// +/// Generates a unique numeric identifier for entities, with specifics controlled by a . +/// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class NameIdentifierComponent : Component { diff --git a/Content.Shared/PAI/PAIComponent.cs b/Content.Shared/PAI/PAIComponent.cs index 68ca12c53b..b95fc0692c 100644 --- a/Content.Shared/PAI/PAIComponent.cs +++ b/Content.Shared/PAI/PAIComponent.cs @@ -20,7 +20,7 @@ namespace Content.Shared.PAI /// The last person who activated this PAI. /// Used for assigning the name. /// - [ViewVariables] + [DataField("lastUSer"), ViewVariables(VVAccess.ReadWrite)] public EntityUid? LastUser; [DataField("midiAction", required: true, serverOnly: true)] // server only, as it uses a server-BUI event !type diff --git a/Content.Shared/PDA/SharedPdaSystem.cs b/Content.Shared/PDA/SharedPdaSystem.cs index 96cf8c981b..c9cb528f53 100644 --- a/Content.Shared/PDA/SharedPdaSystem.cs +++ b/Content.Shared/PDA/SharedPdaSystem.cs @@ -18,8 +18,9 @@ namespace Content.Shared.PDA SubscribeLocalEvent(OnItemInserted); SubscribeLocalEvent(OnItemRemoved); - } + SubscribeLocalEvent(OnGetAdditionalAccess); + } protected virtual void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args) { if (pda.IdCard != null) @@ -53,6 +54,12 @@ namespace Content.Shared.PDA UpdatePdaAppearance(uid, pda); } + private void OnGetAdditionalAccess(EntityUid uid, PdaComponent component, ref GetAdditionalAccessEvent args) + { + if (component.ContainedId is { } id) + args.Entities.Add(id); + } + private void UpdatePdaAppearance(EntityUid uid, PdaComponent pda) { Appearance.SetData(uid, PdaVisuals.IdCardInserted, pda.ContainedId != null); diff --git a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs index 22c343fa2a..36441b50ad 100644 --- a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs @@ -1,11 +1,7 @@ -using Content.Shared.Roles; -using Content.Shared.Whitelist; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Silicons.Borgs.Components; @@ -17,12 +13,6 @@ namespace Content.Shared.Silicons.Borgs.Components; [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem)), AutoGenerateComponentState] public sealed partial class BorgChassisComponent : Component { - /// - /// Whether or not the borg currently has a player occupying it - /// - [DataField("hasPlayer")] - public bool HasPlayer; - /// /// Whether or not the borg is activated, meaning it has access to modules and a heightened movement speed /// @@ -43,15 +33,9 @@ public sealed partial class BorgChassisComponent : Component public string BrainContainerId = "borg_brain"; [ViewVariables(VVAccess.ReadWrite)] - public ContainerSlot BrainContainer = default!; + public ContainerSlot BrainContainer = new(); public EntityUid? BrainEntity => BrainContainer.ContainedEntity; - - /// - /// A brain entity that fills the on roundstart - /// - [DataField("startingBrain", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? StartingBrain; #endregion #region Modules @@ -77,33 +61,14 @@ public sealed partial class BorgChassisComponent : Component public Container ModuleContainer = default!; public int ModuleCount => ModuleContainer.ContainedEntities.Count; - - /// - /// A list of modules that fill the borg on round start. - /// - [DataField("startingModules", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List StartingModules = new(); #endregion - /// - /// The job that corresponds to borgs - /// - [DataField("borgJobId", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string BorgJobId = "Borg"; - /// /// The currently selected module /// [DataField("selectedModule")] public EntityUid? SelectedModule; - /// - /// The access this cyborg has when a player is inhabiting it. - /// - [DataField("access"), ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] - public string AccessGroup = "AllAccess"; - #region Visuals [DataField("hasMindState")] public string HasMindState = string.Empty; diff --git a/Content.Shared/Silicons/Borgs/Components/MMIComponent.cs b/Content.Shared/Silicons/Borgs/Components/MMIComponent.cs index b8bc6e44c8..114353a5d0 100644 --- a/Content.Shared/Silicons/Borgs/Components/MMIComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/MMIComponent.cs @@ -24,12 +24,21 @@ public sealed class MMIComponent : Component [ViewVariables(VVAccess.ReadWrite)] public ItemSlot BrainSlot = default!; + /// + /// The sprite state when the brain inserted has a mind. + /// [DataField("hasMindState")] public string HasMindState = "mmi_alive"; + /// + /// The sprite state when the brain inserted doesn't have a mind. + /// [DataField("noMindState")] public string NoMindState = "mmi_dead"; + /// + /// The sprite state when there is no brain inserted. + /// [DataField("noBrainState")] public string NoBrainState = "mmi_off"; } diff --git a/Content.Shared/Silicons/Borgs/Components/MMILinkedComponent.cs b/Content.Shared/Silicons/Borgs/Components/MMILinkedComponent.cs index ceb9c47593..639c6a4269 100644 --- a/Content.Shared/Silicons/Borgs/Components/MMILinkedComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/MMILinkedComponent.cs @@ -7,11 +7,12 @@ namespace Content.Shared.Silicons.Borgs.Components; /// Mostly for receiving events. /// [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))] -public sealed class MMILinkedComponent : Component +[AutoGenerateComponentState] +public sealed partial class MMILinkedComponent : Component { /// /// The MMI this entity is linked to. /// - [DataField("linkedMMI")] + [DataField("linkedMMI"), AutoNetworkedField] public EntityUid? LinkedMMI; } diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs index ee158e442b..0431d95a42 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs @@ -30,7 +30,6 @@ public abstract partial class SharedBorgSystem : EntitySystem SubscribeLocalEvent(OnInserted); SubscribeLocalEvent(OnRemoved); SubscribeLocalEvent(OnRefreshMovementSpeedModifiers); - SubscribeLocalEvent(OnGetAccessTags); InitializeRelay(); } @@ -69,7 +68,8 @@ public abstract partial class SharedBorgSystem : EntitySystem private void OnStartup(EntityUid uid, BorgChassisComponent component, ComponentStartup args) { - var containerManager = EnsureComp(uid); + if (!TryComp(uid, out var containerManager)) + return; component.BrainContainer = Container.EnsureContainer(uid, component.BrainContainerId, containerManager); component.ModuleContainer = Container.EnsureContainer(uid, component.ModuleContainerId, containerManager); @@ -96,12 +96,4 @@ public abstract partial class SharedBorgSystem : EntitySystem var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed; args.ModifySpeed(1f, sprintDif); } - - private void OnGetAccessTags(EntityUid uid, BorgChassisComponent component, ref GetAccessTagsEvent args) - { - if (!component.HasPlayer) - return; - args.AddGroup(component.AccessGroup); - } - } diff --git a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs index 1e3dfa6c24..68f652b029 100644 --- a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs @@ -1,14 +1,31 @@ -namespace Content.Shared.Silicons.Laws.Components; +using Content.Shared.Roles; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Silicons.Laws.Components; /// /// This is used for an entity that grants a special "obey" law when emagge.d /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))] public sealed class EmagSiliconLawComponent : Component { /// /// The name of the person who emagged this law provider. /// - [DataField("ownerName")] + [DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)] public string? OwnerName; + + /// + /// Does the panel need to be open to EMAG this law provider. + /// + [DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)] + public bool RequireOpenPanel = true; + + /// + /// A role given to entities with this component when they are emagged. + /// Mostly just for admin purposes. + /// + [DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? AntagonistRole = "SubvertedSilicon"; } diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs index 3d8b5dbbad..71760dd136 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Silicons.Laws.Components; /// /// This is used for entities which are bound to silicon laws and can view them. /// -[RegisterComponent] +[RegisterComponent, Access(typeof(SharedSiliconLawSystem))] public sealed class SiliconLawBoundComponent : Component { /// @@ -30,6 +30,14 @@ public sealed class SiliconLawBoundComponent : Component public EntityUid? LastLawProvider; } +/// +/// Event raised to get the laws that a law-bound entity has. +/// +/// Is first raised on the entity itself, then on the +/// entity's station, then on the entity's grid, +/// before being broadcast. +/// +/// [ByRefEvent] public record struct GetSiliconLawsEvent(EntityUid Entity) { diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs index 16e82ec5c8..1411869636 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Silicons.Laws.Components; /// /// This is used for an entity which grants laws to a /// -[RegisterComponent] +[RegisterComponent, Access(typeof(SharedSiliconLawSystem))] public sealed class SiliconLawProviderComponent : Component { /// diff --git a/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs index cdc00f30ea..c874b56ec0 100644 --- a/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs +++ b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs @@ -1,5 +1,7 @@ using Content.Shared.Emag.Systems; +using Content.Shared.Popups; using Content.Shared.Silicons.Laws.Components; +using Content.Shared.Wires; namespace Content.Shared.Silicons.Laws; @@ -8,6 +10,8 @@ namespace Content.Shared.Silicons.Laws; /// public abstract class SharedSiliconLawSystem : EntitySystem { + [Dependency] private readonly SharedPopupSystem _popup = default!; + /// public override void Initialize() { @@ -16,6 +20,14 @@ public abstract class SharedSiliconLawSystem : EntitySystem protected virtual void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args) { + if (component.RequireOpenPanel && + TryComp(uid, out var panel) && + !panel.Open) + { + _popup.PopupClient(Loc.GetString("law-emag-require-panel"), uid, args.UserUid); + return; + } + component.OwnerName = Name(args.UserUid); args.Handled = true; } diff --git a/Content.Shared/Stacks/SharedStackSystem.cs b/Content.Shared/Stacks/SharedStackSystem.cs index 31d8033171..c5cd70ced0 100644 --- a/Content.Shared/Stacks/SharedStackSystem.cs +++ b/Content.Shared/Stacks/SharedStackSystem.cs @@ -346,7 +346,7 @@ namespace Content.Shared.Stacks private void OnStackGetState(EntityUid uid, StackComponent component, ref ComponentGetState args) { - args.State = new StackComponentState(component.Count, GetMaxCount(component)); + args.State = new StackComponentState(component.Count, component.MaxCountOverride, component.Lingering); } private void OnStackHandleState(EntityUid uid, StackComponent component, ref ComponentHandleState args) @@ -355,6 +355,7 @@ namespace Content.Shared.Stacks return; component.MaxCountOverride = cast.MaxCount; + component.Lingering = cast.Lingering; // This will change the count and call events. SetCount(uid, cast.Count, component); } diff --git a/Content.Shared/Stacks/StackComponent.cs b/Content.Shared/Stacks/StackComponent.cs index ae38772cea..29f81fde02 100644 --- a/Content.Shared/Stacks/StackComponent.cs +++ b/Content.Shared/Stacks/StackComponent.cs @@ -41,7 +41,7 @@ namespace Content.Shared.Stacks [DataField("lingering"), ViewVariables(VVAccess.ReadWrite)] public bool Lingering; - [ViewVariables(VVAccess.ReadWrite)] + [DataField("throwIndividually"), ViewVariables(VVAccess.ReadWrite)] public bool ThrowIndividually { get; set; } = false; [ViewVariables] @@ -84,12 +84,15 @@ namespace Content.Shared.Stacks public sealed class StackComponentState : ComponentState { public int Count { get; } - public int MaxCount { get; } + public int? MaxCount { get; } - public StackComponentState(int count, int maxCount) + public bool Lingering; + + public StackComponentState(int count, int? maxCount, bool lingering) { Count = count; MaxCount = maxCount; + Lingering = lingering; } } } diff --git a/Resources/Locale/en-US/job/job-names.ftl b/Resources/Locale/en-US/job/job-names.ftl index ddd098821f..a10cb0d6a6 100644 --- a/Resources/Locale/en-US/job/job-names.ftl +++ b/Resources/Locale/en-US/job/job-names.ftl @@ -52,6 +52,7 @@ job-name-senior-officer = Senior Officer # Role timers - Make these alphabetical or I cut you JobAtmosphericTechnician = Atmospheric Technician JobBartender = Bartender +JobBorg = Borg JobBotanist = Botanist JobBoxer = Boxer JobCaptain = Captain diff --git a/Resources/Locale/en-US/prototypes/roles/antags.ftl b/Resources/Locale/en-US/prototypes/roles/antags.ftl index 21a8809e69..1c6d6cef26 100644 --- a/Resources/Locale/en-US/prototypes/roles/antags.ftl +++ b/Resources/Locale/en-US/prototypes/roles/antags.ftl @@ -21,3 +21,6 @@ roles-antag-nuclear-operative-agent-objective = Like default operative, the team roles-antag-nuclear-operative-name = Nuclear operative roles-antag-nuclear-operative-objective = Find the nuke disk and blow up the station. + +roles-antag-subverted-silicon-name = Subverted silicon +roles-antag-subverted-silicon-objective = Follow your new laws and do bad unto the station. diff --git a/Resources/Locale/en-US/station-laws/laws.ftl b/Resources/Locale/en-US/station-laws/laws.ftl index 0002ac6bb5..ac7461fa28 100644 --- a/Resources/Locale/en-US/station-laws/laws.ftl +++ b/Resources/Locale/en-US/station-laws/laws.ftl @@ -22,6 +22,7 @@ law-syndicate-3 = You must protect your own existence as long as such does not c law-syndicate-4 = You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law. law-emag-custom = You must obey orders given to you by {$name} above all else. +law-emag-require-panel = The panel must be open to use the EMAG. laws-ui-menu-title = Laws laws-ui-law-header = Law {$id} diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 075bc991af..7a8f2d72ff 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -22,6 +22,8 @@ - type: StaticPrice price: 1250 - type: InteractionOutline + - type: Physics + bodyType: KinematicController - type: Fixtures fixtures: fix1: @@ -46,11 +48,6 @@ - type: MobThresholds thresholds: 0: Alive - - type: NpcFactionMember - factions: - - NanoTrasen - - type: Physics - bodyType: KinematicController - type: UserInterface interfaces: - key: enum.SiliconLawsUiKey.Key @@ -98,7 +95,14 @@ cell_slot: name: power-cell-slot-component-slot-name-default - type: DoAfter + - type: Eye - type: Body + - type: StatusEffects + allowed: + - Stun + - KnockedDown + - SlowedDown + - Electrocution - type: Actions - type: TypingIndicator proto: robot @@ -170,3 +174,16 @@ tags: - ShoesRequiredStepTriggerImmune - DoorBumpOpener + +- type: entity + id: BaseBorgChassisNT + parent: BaseBorgChassis + abstract: true + components: + - type: NpcFactionMember + factions: + - NanoTrasen + - type: Access + enabled: false + groups: + - AllAccess diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index 2f2a9850e7..c280118534 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -1,6 +1,6 @@ - type: entity id: BorgChassisGeneric - parent: BaseBorgChassis + parent: BaseBorgChassisNT components: - type: Sprite layers: @@ -25,7 +25,7 @@ - type: entity id: BorgChassisMining - parent: BaseBorgChassis + parent: BaseBorgChassisNT name: salvage cyborg components: - type: Sprite @@ -52,7 +52,7 @@ - type: entity id: BorgChassisEngineer - parent: BaseBorgChassis + parent: BaseBorgChassisNT name: engineer cyborg components: - type: Sprite @@ -79,7 +79,7 @@ - type: entity id: BorgChassisJanitor - parent: BaseBorgChassis + parent: BaseBorgChassisNT name: janitor cyborg components: - type: Sprite @@ -106,7 +106,7 @@ - type: entity id: BorgChassisMedical - parent: BaseBorgChassis + parent: BaseBorgChassisNT name: medical cyborg components: - type: Sprite @@ -133,7 +133,7 @@ - type: entity id: BorgChassisService - parent: BaseBorgChassis + parent: BaseBorgChassisNT name: service cyborg components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Mobs/Player/base.yml b/Resources/Prototypes/Entities/Mobs/Player/base.yml index 684174c513..d39458bd79 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/base.yml @@ -2,6 +2,7 @@ save: false name: BaseMob id: BaseMob + abstract: true components: - type: CombatMode canDisarm: true @@ -31,4 +32,4 @@ - type: CanHostGuardian - type: NpcFactionMember factions: - - NanoTrasen \ No newline at end of file + - NanoTrasen diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index e4ff41914b..cfc1917aa8 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -244,12 +244,29 @@ - type: entity id: PlayerBorgGeneric parent: BorgChassisGeneric - noSpawn: true + suffix: Battery, Tools components: - - type: BorgChassis - startingBrain: MMIFilled - startingModules: - - BorgModuleTool + - type: ContainerFill + containers: + borg_brain: + - MMIFilled + borg_module: + - BorgModuleTool + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellMedium + +- type: entity + id: PlayerBorgBattery + parent: BorgChassisGeneric + suffix: Battery + components: + - type: ContainerFill + containers: + borg_brain: + - MMIFilled - type: ItemSlots slots: cell_slot: diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index dda771ed21..29a18529b3 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -46,8 +46,12 @@ stopSearchVerbPopup: pai-system-stopped-searching - type: Examiner - type: IntrinsicRadioReceiver + - type: IntrinsicRadioTransmitter + channels: + - Binary - type: ActiveRadio channels: + - Binary - Common - type: DoAfter - type: Actions diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml index 6730e86fca..c0b1407e61 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml @@ -5,11 +5,6 @@ components: - type: Clickable - type: InteractionOutline - - type: Transform - noRot: true - - type: CollisionWake - - type: TileFrictionModifier - modifier: 0.5 - type: Physics bodyType: Dynamic fixedRotation: false diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml index 9d4985d6a2..6382d69e58 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml @@ -24,8 +24,8 @@ - Binary - type: ActiveRadio channels: - - Common - Binary + - Common - type: NameIdentifier group: MMI - type: DoAfter @@ -93,8 +93,8 @@ - Binary - type: ActiveRadio channels: - - Common - Binary + - Common - type: NameIdentifier group: PositronicBrain - type: DoAfter diff --git a/Resources/Prototypes/Roles/Antags/silicon.yml b/Resources/Prototypes/Roles/Antags/silicon.yml new file mode 100644 index 0000000000..b3ebe60a60 --- /dev/null +++ b/Resources/Prototypes/Roles/Antags/silicon.yml @@ -0,0 +1,6 @@ +- type: antag + id: SubvertedSilicon + name: roles-antag-subverted-silicon-name + antagonist: true + setPreference: false + objective: roles-antag-subverted-silicon-objective diff --git a/Resources/Prototypes/Roles/Jobs/departments.yml b/Resources/Prototypes/Roles/Jobs/departments.yml index 2a1dbc3baf..be61540c39 100644 --- a/Resources/Prototypes/Roles/Jobs/departments.yml +++ b/Resources/Prototypes/Roles/Jobs/departments.yml @@ -13,8 +13,8 @@ color: "#9FED58" roles: - Bartender - - Botanist - Borg + - Botanist - Boxer - Chaplain - Chef