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
This commit is contained in:
Nemanja
2023-08-14 19:34:23 -04:00
committed by GitHub
parent 8b0eb7e4de
commit 7ddee71379
40 changed files with 299 additions and 175 deletions

View File

@@ -1,4 +1,3 @@
using Content.Shared.Random.Helpers;
using Robust.Server.Containers; using Robust.Server.Containers;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -13,9 +12,6 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
[DataField("containers")] [DataField("containers")]
public List<string> Containers = new(); public List<string> Containers = new();
[DataField("randomOffset")]
public float RandomOffset = 0.25f;
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{ {
if (!system.EntityManager.TryGetComponent<ContainerManagerComponent>(owner, out var containerManager)) if (!system.EntityManager.TryGetComponent<ContainerManagerComponent>(owner, out var containerManager))
@@ -29,11 +25,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
if (!containerSys.TryGetContainer(owner, containerId, out var container, containerManager)) if (!containerSys.TryGetContainer(owner, containerId, out var container, containerManager))
continue; continue;
var entities = containerSys.EmptyContainer(container, true); containerSys.EmptyContainer(container, true);
foreach (var ent in entities)
{
ent.RandomOffset(RandomOffset);
}
} }
} }
} }

View File

@@ -5,6 +5,7 @@ using Content.Server.Popups;
using Content.Server.Stunnable; using Content.Server.Stunnable;
using Content.Shared.Charges.Components; using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems; using Content.Shared.Charges.Systems;
using Content.Shared.Damage;
using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Flash; using Content.Shared.Flash;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
@@ -43,7 +44,6 @@ namespace Content.Server.Flash
SubscribeLocalEvent<FlashComponent, MeleeHitEvent>(OnFlashMeleeHit); SubscribeLocalEvent<FlashComponent, MeleeHitEvent>(OnFlashMeleeHit);
// ran before toggling light for extra-bright lantern // ran before toggling light for extra-bright lantern
SubscribeLocalEvent<FlashComponent, UseInHandEvent>(OnFlashUseInHand, before: new []{ typeof(HandheldLightSystem) }); SubscribeLocalEvent<FlashComponent, UseInHandEvent>(OnFlashUseInHand, before: new []{ typeof(HandheldLightSystem) });
SubscribeLocalEvent<InventoryComponent, FlashAttemptEvent>(OnInventoryFlashAttempt); SubscribeLocalEvent<InventoryComponent, FlashAttemptEvent>(OnInventoryFlashAttempt);
SubscribeLocalEvent<FlashImmunityComponent, FlashAttemptEvent>(OnFlashImmunityFlashAttempt); SubscribeLocalEvent<FlashImmunityComponent, FlashAttemptEvent>(OnFlashImmunityFlashAttempt);

View File

@@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// This is used for a ghost role which can be toggled on and off at will, like a PAI. /// This is used for a ghost role which can be toggled on and off at will, like a PAI.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, Access(typeof(ToggleableGhostRoleSystem))]
public sealed class ToggleableGhostRoleComponent : Component public sealed class ToggleableGhostRoleComponent : Component
{ {
[DataField("examineTextMindPresent")] [DataField("examineTextMindPresent")]

View File

@@ -1,4 +1,5 @@
using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Components;
using Content.Server.Mind;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.PAI; using Content.Server.PAI;
using Content.Shared.Examine; using Content.Shared.Examine;
@@ -16,6 +17,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
{ {
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedPopupSystem _popup = 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 //todo this really shouldn't be in here but this system was converted from PAIs
[Dependency] private readonly PAISystem _pai = default!; [Dependency] private readonly PAISystem _pai = default!;
@@ -79,7 +81,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
private void OnMindAdded(EntityUid uid, ToggleableGhostRoleComponent pai, MindAddedMessage args) 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 // Mind was added, shutdown the ghost role stuff so it won't get in the way
RemComp<GhostTakeoverAvailableComponent>(uid); RemCompDeferred<GhostTakeoverAvailableComponent>(uid);
UpdateAppearance(uid, ToggleableGhostRoleStatus.On); UpdateAppearance(uid, ToggleableGhostRoleStatus.On);
} }
@@ -105,12 +107,12 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
Text = Loc.GetString(component.WipeVerbText), Text = Loc.GetString(component.WipeVerbText),
Act = () => Act = () =>
{ {
if (component.Deleted || !HasComp<MindContainerComponent>(uid)) if (!TryComp<MindContainerComponent>(uid, out var mindComp) || mindComp.Mind == null)
return; return;
// Wiping device :( // Wiping device :(
// The shutdown of the Mind should cause automatic reset of the pAI during OnMindRemoved // The shutdown of the Mind should cause automatic reset of the pAI during OnMindRemoved
// EDIT: But it doesn't!!!! Wtf? Do stuff manually // EDIT: But it doesn't!!!! Wtf? Do stuff manually
RemComp<MindContainerComponent>(uid); _mind.TransferTo(mindComp.Mind, null);
_popup.PopupEntity(Loc.GetString(component.WipeVerbPopup), uid, args.User, PopupType.Large); _popup.PopupEntity(Loc.GetString(component.WipeVerbPopup), uid, args.User, PopupType.Large);
UpdateAppearance(uid, ToggleableGhostRoleStatus.Off); UpdateAppearance(uid, ToggleableGhostRoleStatus.Off);
_pai.PAITurningOff(uid); _pai.PAITurningOff(uid);
@@ -127,8 +129,8 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
{ {
if (component.Deleted || !HasComp<GhostTakeoverAvailableComponent>(uid)) if (component.Deleted || !HasComp<GhostTakeoverAvailableComponent>(uid))
return; return;
RemComp<GhostTakeoverAvailableComponent>(uid); RemCompDeferred<GhostTakeoverAvailableComponent>(uid);
RemComp<GhostRoleComponent>(uid); RemCompDeferred<GhostRoleComponent>(uid);
_popup.PopupEntity(Loc.GetString(component.StopSearchVerbPopup), uid, args.User); _popup.PopupEntity(Loc.GetString(component.StopSearchVerbPopup), uid, args.User);
UpdateAppearance(uid, ToggleableGhostRoleStatus.Off); UpdateAppearance(uid, ToggleableGhostRoleStatus.Off);
_pai.PAITurningOff(uid); _pai.PAITurningOff(uid);

View File

@@ -40,6 +40,12 @@ namespace Content.Server.Mind.Components
public sealed class MindRemovedMessage : EntityEventArgs public sealed class MindRemovedMessage : EntityEventArgs
{ {
public Mind OldMind;
public MindRemovedMessage(Mind oldMind)
{
OldMind = oldMind;
}
} }
public sealed class MindAddedMessage : EntityEventArgs public sealed class MindAddedMessage : EntityEventArgs

View File

@@ -30,6 +30,7 @@ public sealed class MindSystem : EntitySystem
[Dependency] private readonly ActorSystem _actor = default!; [Dependency] private readonly ActorSystem _actor = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly GhostSystem _ghostSystem = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
@@ -125,11 +126,12 @@ public sealed class MindSystem : EntitySystem
/// </summary> /// </summary>
private void InternalEjectMind(EntityUid uid, MindContainerComponent? mind = null) private void InternalEjectMind(EntityUid uid, MindContainerComponent? mind = null)
{ {
if (!Resolve(uid, ref mind, false)) if (!Resolve(uid, ref mind, false) || mind.Mind == null)
return; return;
var oldMind = mind.Mind;
mind.Mind = null; mind.Mind = null;
RaiseLocalEvent(uid, new MindRemovedMessage(), true); RaiseLocalEvent(uid, new MindRemovedMessage(oldMind), true);
} }
private void OnVisitingTerminating(EntityUid uid, VisitingMindComponent component, ref EntityTerminatingEvent args) private void OnVisitingTerminating(EntityUid uid, VisitingMindComponent component, ref EntityTerminatingEvent args)
@@ -159,7 +161,7 @@ public sealed class MindSystem : EntitySystem
return; return;
} }
TransferTo(mind, null); TransferTo(mind, null, createGhost: false);
if (component.GhostOnShutdown && mind.Session != null) 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. // 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."); 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; return;
} }
@@ -381,7 +383,7 @@ public sealed class MindSystem : EntitySystem
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// Thrown if <paramref name="entity"/> is already owned by another mind. /// Thrown if <paramref name="entity"/> is already owned by another mind.
/// </exception> /// </exception>
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) if (entity == mind.OwnedEntity)
return; return;
@@ -407,6 +409,16 @@ public sealed class MindSystem : EntitySystem
alreadyAttached = true; 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<GhostComponent>(entity.Value);
_ghostSystem.SetCanReturnToBody(ghostComponent, false);
}
var oldComp = mind.OwnedComponent; var oldComp = mind.OwnedComponent;
var oldEntity = mind.OwnedEntity; var oldEntity = mind.OwnedEntity;

View File

@@ -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) { }
}

View File

@@ -38,6 +38,7 @@ public sealed partial class BorgSystem
var ent = args.Entity; var ent = args.Entity;
var linked = EnsureComp<MMILinkedComponent>(ent); var linked = EnsureComp<MMILinkedComponent>(ent);
linked.LinkedMMI = uid; linked.LinkedMMI = uid;
Dirty(uid, component);
if (_mind.TryGetMind(ent, out var mind)) if (_mind.TryGetMind(ent, out var mind))
_mind.TransferTo(mind, uid, true); _mind.TransferTo(mind, uid, true);

View File

@@ -6,6 +6,7 @@ using Content.Server.Mind;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.PowerCell; using Content.Server.PowerCell;
using Content.Server.UserInterface; using Content.Server.UserInterface;
using Content.Shared.Access.Systems;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
@@ -13,6 +14,7 @@ using Content.Shared.Interaction;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Content.Shared.PowerCell; using Content.Shared.PowerCell;
using Content.Shared.PowerCell.Components; using Content.Shared.PowerCell.Components;
using Content.Shared.Roles;
using Content.Shared.Silicons.Borgs; using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Throwing; using Content.Shared.Throwing;
@@ -30,6 +32,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
[Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly IBanManager _banManager = default!; [Dependency] private readonly IBanManager _banManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAccessSystem _access = default!;
[Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = 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 ThrowingSystem _throwing = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!;
[ValidatePrototypeId<JobPrototype>]
public const string BorgJobId = "Borg";
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
@@ -66,18 +72,6 @@ public sealed partial class BorgSystem : SharedBorgSystem
{ {
UpdateBatteryAlert(uid); UpdateBatteryAlert(uid);
_movementSpeedModifier.RefreshMovementSpeedModifiers(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) 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 (_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); Popup.PopupEntity(Loc.GetString("borg-player-not-allowed"), used, args.User);
return; return;
@@ -218,7 +212,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
if (!_mind.TryGetMind(uid, out var mind) || mind.Session == null) if (!_mind.TryGetMind(uid, out var mind) || mind.Session == null)
return; return;
if (!CanPlayerBeBorgged(mind.Session, chassisComponent)) if (!CanPlayerBeBorgged(mind.Session))
{ {
Popup.PopupEntity(Loc.GetString("borg-player-not-allowed-eject"), uid); Popup.PopupEntity(Loc.GetString("borg-player-not-allowed-eject"), uid);
Container.RemoveEntity(containerEnt, uid); Container.RemoveEntity(containerEnt, uid);
@@ -284,9 +278,9 @@ public sealed partial class BorgSystem : SharedBorgSystem
/// </summary> /// </summary>
public void BorgActivate(EntityUid uid, BorgChassisComponent component) public void BorgActivate(EntityUid uid, BorgChassisComponent component)
{ {
component.HasPlayer = true;
Popup.PopupEntity(Loc.GetString("borg-mind-added", ("name", Identity.Name(uid, EntityManager))), uid); Popup.PopupEntity(Loc.GetString("borg-mind-added", ("name", Identity.Name(uid, EntityManager))), uid);
_powerCell.SetPowerCellDrawEnabled(uid, true); _powerCell.SetPowerCellDrawEnabled(uid, true);
_access.SetAccessEnabled(uid, true);
_appearance.SetData(uid, BorgVisuals.HasPlayer, true); _appearance.SetData(uid, BorgVisuals.HasPlayer, true);
Dirty(uid, component); Dirty(uid, component);
} }
@@ -296,9 +290,9 @@ public sealed partial class BorgSystem : SharedBorgSystem
/// </summary> /// </summary>
public void BorgDeactivate(EntityUid uid, BorgChassisComponent component) public void BorgDeactivate(EntityUid uid, BorgChassisComponent component)
{ {
component.HasPlayer = false;
Popup.PopupEntity(Loc.GetString("borg-mind-removed", ("name", Identity.Name(uid, EntityManager))), uid); Popup.PopupEntity(Loc.GetString("borg-mind-removed", ("name", Identity.Name(uid, EntityManager))), uid);
_powerCell.SetPowerCellDrawEnabled(uid, false); _powerCell.SetPowerCellDrawEnabled(uid, false);
_access.SetAccessEnabled(uid, false);
_appearance.SetData(uid, BorgVisuals.HasPlayer, false); _appearance.SetData(uid, BorgVisuals.HasPlayer, false);
Dirty(uid, component); 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. /// 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. /// If they don't have enough hours, they cannot be placed into a chassis.
/// </summary> /// </summary>
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 false;
return true; return true;

View File

@@ -1,7 +1,10 @@
using Content.Server.Administration; using System.Linq;
using Content.Server.Administration;
using Content.Server.Chat.Managers; using Content.Server.Chat.Managers;
using Content.Server.GameTicking; using Content.Server.GameTicking;
using Content.Server.Mind;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.Roles;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.Actions.ActionTypes; using Content.Shared.Actions.ActionTypes;
@@ -10,8 +13,10 @@ using Content.Shared.Chat;
using Content.Shared.Emag.Components; using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems; using Content.Shared.Emag.Systems;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Roles;
using Content.Shared.Silicons.Laws; using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components; using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Wires;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -24,6 +29,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
{ {
[Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!; [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
@@ -35,6 +41,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
SubscribeLocalEvent<SiliconLawBoundComponent, ComponentStartup>(OnComponentStartup); SubscribeLocalEvent<SiliconLawBoundComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<SiliconLawBoundComponent, ComponentShutdown>(OnComponentShutdown); SubscribeLocalEvent<SiliconLawBoundComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<SiliconLawBoundComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SiliconLawBoundComponent, MindAddedMessage>(OnMindAdded); SubscribeLocalEvent<SiliconLawBoundComponent, MindAddedMessage>(OnMindAdded);
SubscribeLocalEvent<SiliconLawBoundComponent, ToggleLawsScreenEvent>(OnToggleLawsScreen); SubscribeLocalEvent<SiliconLawBoundComponent, ToggleLawsScreenEvent>(OnToggleLawsScreen);
SubscribeLocalEvent<SiliconLawBoundComponent, BoundUIOpenedEvent>(OnBoundUIOpened); SubscribeLocalEvent<SiliconLawBoundComponent, BoundUIOpenedEvent>(OnBoundUIOpened);
@@ -42,8 +49,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws); SubscribeLocalEvent<SiliconLawProviderComponent, GetSiliconLawsEvent>(OnDirectedGetLaws);
SubscribeLocalEvent<EmagSiliconLawComponent, GetSiliconLawsEvent>(OnDirectedEmagGetLaws); SubscribeLocalEvent<EmagSiliconLawComponent, GetSiliconLawsEvent>(OnDirectedEmagGetLaws);
SubscribeLocalEvent<EmagSiliconLawComponent, MindAddedMessage>(OnEmagMindAdded);
SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved);
SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined);
} }
private void OnComponentStartup(EntityUid uid, SiliconLawBoundComponent component, ComponentStartup args) private void OnComponentStartup(EntityUid uid, SiliconLawBoundComponent component, ComponentStartup args)
{ {
component.ProvidedAction = new (_prototype.Index<InstantActionPrototype>(component.ViewLawsAction)); component.ProvidedAction = new (_prototype.Index<InstantActionPrototype>(component.ViewLawsAction));
@@ -56,6 +66,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
_actions.RemoveAction(uid, component.ProvidedAction); _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) private void OnMindAdded(EntityUid uid, SiliconLawBoundComponent component, MindAddedMessage args)
{ {
if (!TryComp<ActorComponent>(uid, out var actor)) if (!TryComp<ActorComponent>(uid, out var actor))
@@ -117,13 +132,47 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid)) if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid))
return; return;
if (component.RequireOpenPanel && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
return;
args.PushMarkup(Loc.GetString("laws-compromised-examine")); args.PushMarkup(Loc.GetString("laws-compromised-examine"));
} }
protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args) protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
{ {
if (component.RequireOpenPanel && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
return;
base.OnGotEmagged(uid, component, ref args); base.OnGotEmagged(uid, component, ref args);
NotifyLawsChanged(uid); NotifyLawsChanged(uid);
EnsureEmaggedRole(uid, component);
}
private void OnEmagMindAdded(EntityUid uid, EmagSiliconLawComponent component, MindAddedMessage args)
{
if (HasComp<EmaggedComponent>(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<SubvertedSiliconRole>(mind))
return;
_mind.AddRole(mind, new SubvertedSiliconRole(mind, _prototype.Index<AntagPrototype>(component.AntagonistRole)));
} }
public List<SiliconLaw> GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) public List<SiliconLaw> GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null)
@@ -131,8 +180,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
if (!Resolve(uid, ref component)) if (!Resolve(uid, ref component))
return new List<SiliconLaw>(); return new List<SiliconLaw>();
var xform = Transform(uid);
var ev = new GetSiliconLawsEvent(uid); var ev = new GetSiliconLawsEvent(uid);
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
@@ -142,6 +189,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
return ev.Laws; return ev.Laws;
} }
var xform = Transform(uid);
if (_station.GetOwningStation(uid, xform) is { } station) if (_station.GetOwningStation(uid, xform) is { } station)
{ {
RaiseLocalEvent(station, ref ev); RaiseLocalEvent(station, ref ev);
@@ -188,7 +237,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
var msg = Loc.GetString("laws-update-notify"); var msg = Loc.GetString("laws-update-notify");
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg)); 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);
} }
} }

View File

@@ -24,6 +24,7 @@ public sealed class WiresSystem : SharedWiresSystem
{ {
[Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly ActivatableUISystem _activatableUI = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
@@ -511,10 +512,7 @@ public sealed class WiresSystem : SharedWiresSystem
if (args.Open == component.RequireOpen) if (args.Open == component.RequireOpen)
return; return;
if (!TryComp<ActivatableUIComponent>(uid, out var ui) || ui.Key == null) _activatableUI.CloseAll(uid);
return;
_uiSystem.TryCloseAll(uid, ui.Key);
} }
private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args) private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args)

View File

@@ -10,17 +10,27 @@ namespace Content.Shared.Access.Components
/// </summary> /// </summary>
[RegisterComponent, NetworkedComponent] [RegisterComponent, NetworkedComponent]
[Access(typeof(SharedAccessSystem))] [Access(typeof(SharedAccessSystem))]
public sealed class AccessComponent : Component [AutoGenerateComponentState]
public sealed partial class AccessComponent : Component
{ {
/// <summary>
/// True if the access provider is enabled and can grant access.
/// </summary>
[DataField("enabled"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public bool Enabled = true;
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))] [DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
[Access(typeof(SharedAccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends [Access(typeof(SharedAccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
[AutoNetworkedField(true)]
public HashSet<string> Tags = new(); public HashSet<string> Tags = new();
/// <summary> /// <summary>
/// Access Groups. These are added to the tags during map init. After map init this will have no effect. /// Access Groups. These are added to the tags during map init. After map init this will have no effect.
/// </summary> /// </summary>
[DataField("groups", readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessGroupPrototype>))] [DataField("groups", readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessGroupPrototype>))]
public readonly HashSet<string> Groups = new(); [AutoNetworkedField(true)]
public HashSet<string> Groups = new();
} }
/// <summary> /// <summary>

View File

@@ -8,9 +8,9 @@ using Content.Shared.PDA;
using Content.Shared.StationRecords; using Content.Shared.StationRecords;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Robust.Shared.Collections;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Shared.Access.Systems; namespace Content.Shared.Access.Systems;
@@ -69,6 +69,8 @@ public sealed class AccessReaderSystem : EntitySystem
/// required entity. /// required entity.
/// </summary> /// </summary>
/// <param name="target">The entity to search for a container</param> /// <param name="target">The entity to search for a container</param>
/// <param name="accessReader"></param>
/// <param name="result"></param>
private bool FindAccessReadersInContainer(EntityUid target, AccessReaderComponent accessReader, out List<AccessReaderComponent> result) private bool FindAccessReadersInContainer(EntityUid target, AccessReaderComponent accessReader, out List<AccessReaderComponent> result)
{ {
result = new(); result = new();
@@ -171,6 +173,11 @@ public sealed class AccessReaderSystem : EntitySystem
{ {
FindAccessItemsInventory(uid, out var items); FindAccessItemsInventory(uid, out var items);
foreach (var item in new ValueList<EntityUid>(items))
{
items.UnionWith(FindPotentialAccessItems(item));
}
var ev = new GetAdditionalAccessEvent var ev = new GetAdditionalAccessEvent
{ {
Entities = items Entities = items
@@ -204,6 +211,7 @@ public sealed class AccessReaderSystem : EntitySystem
/// Finds the access tags on the given entity /// Finds the access tags on the given entity
/// </summary> /// </summary>
/// <param name="uid">The entity that is being searched.</param> /// <param name="uid">The entity that is being searched.</param>
/// <param name="recordKeys"></param>
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param> /// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
public bool FindStationRecordKeys(EntityUid uid, out ICollection<StationRecordKey> recordKeys, HashSet<EntityUid>? items = null) public bool FindStationRecordKeys(EntityUid uid, out ICollection<StationRecordKey> recordKeys, HashSet<EntityUid>? items = null)
{ {
@@ -277,17 +285,6 @@ public sealed class AccessReaderSystem : EntitySystem
private bool FindAccessTagsItem(EntityUid uid, out HashSet<string> tags) private bool FindAccessTagsItem(EntityUid uid, out HashSet<string> tags)
{ {
tags = new(); 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<AccessComponent>(id).Tags);
}
var ev = new GetAccessTagsEvent(tags, _prototype); var ev = new GetAccessTagsEvent(tags, _prototype);
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);

View File

@@ -15,28 +15,7 @@ namespace Content.Shared.Access.Systems
base.Initialize(); base.Initialize();
SubscribeLocalEvent<AccessComponent, MapInitEvent>(OnAccessInit); SubscribeLocalEvent<AccessComponent, MapInitEvent>(OnAccessInit);
SubscribeLocalEvent<AccessComponent, ComponentGetState>(OnAccessGetState); SubscribeLocalEvent<AccessComponent, GetAccessTagsEvent>(OnGetAccessTags);
SubscribeLocalEvent<AccessComponent, ComponentHandleState>(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,
};
} }
private void OnAccessInit(EntityUid uid, AccessComponent component, MapInitEvent args) 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);
}
/// <summary> /// <summary>
/// Replaces the set of access tags we have with the provided set. /// Replaces the set of access tags we have with the provided set.
/// </summary> /// </summary>
@@ -122,12 +117,5 @@ namespace Content.Shared.Access.Systems
TryAddGroups(uid, prototype.ExtendedAccessGroups, access); TryAddGroups(uid, prototype.ExtendedAccessGroups, access);
} }
} }
[Serializable, NetSerializable]
private sealed class AccessComponentState : ComponentState
{
public HashSet<string> Tags = new();
public HashSet<string> Groups = new();
}
} }
} }

View File

@@ -6,6 +6,10 @@ using Content.Shared.Movement.Events;
namespace Content.Shared.Interaction; namespace Content.Shared.Interaction;
/// <summary>
/// Handles <see cref="BlockMovementComponent"/>, which prevents various
/// kinds of movement and interactions when attached to an entity.
/// </summary>
public partial class SharedInteractionSystem public partial class SharedInteractionSystem
{ {
public void InitializeBlocking() public void InitializeBlocking()

View File

@@ -3,6 +3,9 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.NameIdentifier; namespace Content.Shared.NameIdentifier;
/// <summary>
/// Generates a unique numeric identifier for entities, with specifics controlled by a <see cref="NameIdentifierGroupPrototype"/>.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class NameIdentifierComponent : Component public sealed partial class NameIdentifierComponent : Component
{ {

View File

@@ -20,7 +20,7 @@ namespace Content.Shared.PAI
/// The last person who activated this PAI. /// The last person who activated this PAI.
/// Used for assigning the name. /// Used for assigning the name.
/// </summary> /// </summary>
[ViewVariables] [DataField("lastUSer"), ViewVariables(VVAccess.ReadWrite)]
public EntityUid? LastUser; public EntityUid? LastUser;
[DataField("midiAction", required: true, serverOnly: true)] // server only, as it uses a server-BUI event !type [DataField("midiAction", required: true, serverOnly: true)] // server only, as it uses a server-BUI event !type

View File

@@ -18,8 +18,9 @@ namespace Content.Shared.PDA
SubscribeLocalEvent<PdaComponent, EntInsertedIntoContainerMessage>(OnItemInserted); SubscribeLocalEvent<PdaComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
SubscribeLocalEvent<PdaComponent, EntRemovedFromContainerMessage>(OnItemRemoved); SubscribeLocalEvent<PdaComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
}
SubscribeLocalEvent<PdaComponent, GetAdditionalAccessEvent>(OnGetAdditionalAccess);
}
protected virtual void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args) protected virtual void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args)
{ {
if (pda.IdCard != null) if (pda.IdCard != null)
@@ -53,6 +54,12 @@ namespace Content.Shared.PDA
UpdatePdaAppearance(uid, 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) private void UpdatePdaAppearance(EntityUid uid, PdaComponent pda)
{ {
Appearance.SetData(uid, PdaVisuals.IdCardInserted, pda.ContainedId != null); Appearance.SetData(uid, PdaVisuals.IdCardInserted, pda.ContainedId != null);

View File

@@ -1,11 +1,7 @@
using Content.Shared.Roles; using Content.Shared.Whitelist;
using Content.Shared.Whitelist;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; 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; namespace Content.Shared.Silicons.Borgs.Components;
@@ -17,12 +13,6 @@ namespace Content.Shared.Silicons.Borgs.Components;
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem)), AutoGenerateComponentState] [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem)), AutoGenerateComponentState]
public sealed partial class BorgChassisComponent : Component public sealed partial class BorgChassisComponent : Component
{ {
/// <summary>
/// Whether or not the borg currently has a player occupying it
/// </summary>
[DataField("hasPlayer")]
public bool HasPlayer;
/// <summary> /// <summary>
/// Whether or not the borg is activated, meaning it has access to modules and a heightened movement speed /// Whether or not the borg is activated, meaning it has access to modules and a heightened movement speed
/// </summary> /// </summary>
@@ -43,15 +33,9 @@ public sealed partial class BorgChassisComponent : Component
public string BrainContainerId = "borg_brain"; public string BrainContainerId = "borg_brain";
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public ContainerSlot BrainContainer = default!; public ContainerSlot BrainContainer = new();
public EntityUid? BrainEntity => BrainContainer.ContainedEntity; public EntityUid? BrainEntity => BrainContainer.ContainedEntity;
/// <summary>
/// A brain entity that fills the <see cref="BrainContainer"/> on roundstart
/// </summary>
[DataField("startingBrain", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? StartingBrain;
#endregion #endregion
#region Modules #region Modules
@@ -77,33 +61,14 @@ public sealed partial class BorgChassisComponent : Component
public Container ModuleContainer = default!; public Container ModuleContainer = default!;
public int ModuleCount => ModuleContainer.ContainedEntities.Count; public int ModuleCount => ModuleContainer.ContainedEntities.Count;
/// <summary>
/// A list of modules that fill the borg on round start.
/// </summary>
[DataField("startingModules", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> StartingModules = new();
#endregion #endregion
/// <summary>
/// The job that corresponds to borgs
/// </summary>
[DataField("borgJobId", customTypeSerializer: typeof(PrototypeIdSerializer<JobPrototype>))]
public string BorgJobId = "Borg";
/// <summary> /// <summary>
/// The currently selected module /// The currently selected module
/// </summary> /// </summary>
[DataField("selectedModule")] [DataField("selectedModule")]
public EntityUid? SelectedModule; public EntityUid? SelectedModule;
/// <summary>
/// The access this cyborg has when a player is inhabiting it.
/// </summary>
[DataField("access"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public string AccessGroup = "AllAccess";
#region Visuals #region Visuals
[DataField("hasMindState")] [DataField("hasMindState")]
public string HasMindState = string.Empty; public string HasMindState = string.Empty;

View File

@@ -24,12 +24,21 @@ public sealed class MMIComponent : Component
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public ItemSlot BrainSlot = default!; public ItemSlot BrainSlot = default!;
/// <summary>
/// The sprite state when the brain inserted has a mind.
/// </summary>
[DataField("hasMindState")] [DataField("hasMindState")]
public string HasMindState = "mmi_alive"; public string HasMindState = "mmi_alive";
/// <summary>
/// The sprite state when the brain inserted doesn't have a mind.
/// </summary>
[DataField("noMindState")] [DataField("noMindState")]
public string NoMindState = "mmi_dead"; public string NoMindState = "mmi_dead";
/// <summary>
/// The sprite state when there is no brain inserted.
/// </summary>
[DataField("noBrainState")] [DataField("noBrainState")]
public string NoBrainState = "mmi_off"; public string NoBrainState = "mmi_off";
} }

View File

@@ -7,11 +7,12 @@ namespace Content.Shared.Silicons.Borgs.Components;
/// Mostly for receiving events. /// Mostly for receiving events.
/// </summary> /// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))] [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))]
public sealed class MMILinkedComponent : Component [AutoGenerateComponentState]
public sealed partial class MMILinkedComponent : Component
{ {
/// <summary> /// <summary>
/// The MMI this entity is linked to. /// The MMI this entity is linked to.
/// </summary> /// </summary>
[DataField("linkedMMI")] [DataField("linkedMMI"), AutoNetworkedField]
public EntityUid? LinkedMMI; public EntityUid? LinkedMMI;
} }

View File

@@ -30,7 +30,6 @@ public abstract partial class SharedBorgSystem : EntitySystem
SubscribeLocalEvent<BorgChassisComponent, EntInsertedIntoContainerMessage>(OnInserted); SubscribeLocalEvent<BorgChassisComponent, EntInsertedIntoContainerMessage>(OnInserted);
SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved); SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved);
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers); SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
SubscribeLocalEvent<BorgChassisComponent, GetAccessTagsEvent>(OnGetAccessTags);
InitializeRelay(); InitializeRelay();
} }
@@ -69,7 +68,8 @@ public abstract partial class SharedBorgSystem : EntitySystem
private void OnStartup(EntityUid uid, BorgChassisComponent component, ComponentStartup args) private void OnStartup(EntityUid uid, BorgChassisComponent component, ComponentStartup args)
{ {
var containerManager = EnsureComp<ContainerManagerComponent>(uid); if (!TryComp<ContainerManagerComponent>(uid, out var containerManager))
return;
component.BrainContainer = Container.EnsureContainer<ContainerSlot>(uid, component.BrainContainerId, containerManager); component.BrainContainer = Container.EnsureContainer<ContainerSlot>(uid, component.BrainContainerId, containerManager);
component.ModuleContainer = Container.EnsureContainer<Container>(uid, component.ModuleContainerId, containerManager); component.ModuleContainer = Container.EnsureContainer<Container>(uid, component.ModuleContainerId, containerManager);
@@ -96,12 +96,4 @@ public abstract partial class SharedBorgSystem : EntitySystem
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed; var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
args.ModifySpeed(1f, sprintDif); args.ModifySpeed(1f, sprintDif);
} }
private void OnGetAccessTags(EntityUid uid, BorgChassisComponent component, ref GetAccessTagsEvent args)
{
if (!component.HasPlayer)
return;
args.AddGroup(component.AccessGroup);
}
} }

View File

@@ -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;
/// <summary> /// <summary>
/// This is used for an entity that grants a special "obey" law when emagge.d /// This is used for an entity that grants a special "obey" law when emagge.d
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class EmagSiliconLawComponent : Component public sealed class EmagSiliconLawComponent : Component
{ {
/// <summary> /// <summary>
/// The name of the person who emagged this law provider. /// The name of the person who emagged this law provider.
/// </summary> /// </summary>
[DataField("ownerName")] [DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)]
public string? OwnerName; public string? OwnerName;
/// <summary>
/// Does the panel need to be open to EMAG this law provider.
/// </summary>
[DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)]
public bool RequireOpenPanel = true;
/// <summary>
/// A role given to entities with this component when they are emagged.
/// Mostly just for admin purposes.
/// </summary>
[DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
public string? AntagonistRole = "SubvertedSilicon";
} }

View File

@@ -8,7 +8,7 @@ namespace Content.Shared.Silicons.Laws.Components;
/// <summary> /// <summary>
/// This is used for entities which are bound to silicon laws and can view them. /// This is used for entities which are bound to silicon laws and can view them.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class SiliconLawBoundComponent : Component public sealed class SiliconLawBoundComponent : Component
{ {
/// <summary> /// <summary>
@@ -30,6 +30,14 @@ public sealed class SiliconLawBoundComponent : Component
public EntityUid? LastLawProvider; public EntityUid? LastLawProvider;
} }
/// <summary>
/// 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.
/// </summary>
/// <param name="Entity"></param>
[ByRefEvent] [ByRefEvent]
public record struct GetSiliconLawsEvent(EntityUid Entity) public record struct GetSiliconLawsEvent(EntityUid Entity)
{ {

View File

@@ -5,7 +5,7 @@ namespace Content.Shared.Silicons.Laws.Components;
/// <summary> /// <summary>
/// This is used for an entity which grants laws to a <see cref="SiliconLawBoundComponent"/> /// This is used for an entity which grants laws to a <see cref="SiliconLawBoundComponent"/>
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class SiliconLawProviderComponent : Component public sealed class SiliconLawProviderComponent : Component
{ {
/// <summary> /// <summary>

View File

@@ -1,5 +1,7 @@
using Content.Shared.Emag.Systems; using Content.Shared.Emag.Systems;
using Content.Shared.Popups;
using Content.Shared.Silicons.Laws.Components; using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Wires;
namespace Content.Shared.Silicons.Laws; namespace Content.Shared.Silicons.Laws;
@@ -8,6 +10,8 @@ namespace Content.Shared.Silicons.Laws;
/// </summary> /// </summary>
public abstract class SharedSiliconLawSystem : EntitySystem public abstract class SharedSiliconLawSystem : EntitySystem
{ {
[Dependency] private readonly SharedPopupSystem _popup = default!;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
@@ -16,6 +20,14 @@ public abstract class SharedSiliconLawSystem : EntitySystem
protected virtual void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args) protected virtual void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
{ {
if (component.RequireOpenPanel &&
TryComp<WiresPanelComponent>(uid, out var panel) &&
!panel.Open)
{
_popup.PopupClient(Loc.GetString("law-emag-require-panel"), uid, args.UserUid);
return;
}
component.OwnerName = Name(args.UserUid); component.OwnerName = Name(args.UserUid);
args.Handled = true; args.Handled = true;
} }

View File

@@ -346,7 +346,7 @@ namespace Content.Shared.Stacks
private void OnStackGetState(EntityUid uid, StackComponent component, ref ComponentGetState args) 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) private void OnStackHandleState(EntityUid uid, StackComponent component, ref ComponentHandleState args)
@@ -355,6 +355,7 @@ namespace Content.Shared.Stacks
return; return;
component.MaxCountOverride = cast.MaxCount; component.MaxCountOverride = cast.MaxCount;
component.Lingering = cast.Lingering;
// This will change the count and call events. // This will change the count and call events.
SetCount(uid, cast.Count, component); SetCount(uid, cast.Count, component);
} }

View File

@@ -41,7 +41,7 @@ namespace Content.Shared.Stacks
[DataField("lingering"), ViewVariables(VVAccess.ReadWrite)] [DataField("lingering"), ViewVariables(VVAccess.ReadWrite)]
public bool Lingering; public bool Lingering;
[ViewVariables(VVAccess.ReadWrite)] [DataField("throwIndividually"), ViewVariables(VVAccess.ReadWrite)]
public bool ThrowIndividually { get; set; } = false; public bool ThrowIndividually { get; set; } = false;
[ViewVariables] [ViewVariables]
@@ -84,12 +84,15 @@ namespace Content.Shared.Stacks
public sealed class StackComponentState : ComponentState public sealed class StackComponentState : ComponentState
{ {
public int Count { get; } 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; Count = count;
MaxCount = maxCount; MaxCount = maxCount;
Lingering = lingering;
} }
} }
} }

View File

@@ -52,6 +52,7 @@ job-name-senior-officer = Senior Officer
# Role timers - Make these alphabetical or I cut you # Role timers - Make these alphabetical or I cut you
JobAtmosphericTechnician = Atmospheric Technician JobAtmosphericTechnician = Atmospheric Technician
JobBartender = Bartender JobBartender = Bartender
JobBorg = Borg
JobBotanist = Botanist JobBotanist = Botanist
JobBoxer = Boxer JobBoxer = Boxer
JobCaptain = Captain JobCaptain = Captain

View File

@@ -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-name = Nuclear operative
roles-antag-nuclear-operative-objective = Find the nuke disk and blow up the station. 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.

View File

@@ -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-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-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-menu-title = Laws
laws-ui-law-header = Law {$id} laws-ui-law-header = Law {$id}

View File

@@ -22,6 +22,8 @@
- type: StaticPrice - type: StaticPrice
price: 1250 price: 1250
- type: InteractionOutline - type: InteractionOutline
- type: Physics
bodyType: KinematicController
- type: Fixtures - type: Fixtures
fixtures: fixtures:
fix1: fix1:
@@ -46,11 +48,6 @@
- type: MobThresholds - type: MobThresholds
thresholds: thresholds:
0: Alive 0: Alive
- type: NpcFactionMember
factions:
- NanoTrasen
- type: Physics
bodyType: KinematicController
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.SiliconLawsUiKey.Key - key: enum.SiliconLawsUiKey.Key
@@ -98,7 +95,14 @@
cell_slot: cell_slot:
name: power-cell-slot-component-slot-name-default name: power-cell-slot-component-slot-name-default
- type: DoAfter - type: DoAfter
- type: Eye
- type: Body - type: Body
- type: StatusEffects
allowed:
- Stun
- KnockedDown
- SlowedDown
- Electrocution
- type: Actions - type: Actions
- type: TypingIndicator - type: TypingIndicator
proto: robot proto: robot
@@ -170,3 +174,16 @@
tags: tags:
- ShoesRequiredStepTriggerImmune - ShoesRequiredStepTriggerImmune
- DoorBumpOpener - DoorBumpOpener
- type: entity
id: BaseBorgChassisNT
parent: BaseBorgChassis
abstract: true
components:
- type: NpcFactionMember
factions:
- NanoTrasen
- type: Access
enabled: false
groups:
- AllAccess

View File

@@ -1,6 +1,6 @@
- type: entity - type: entity
id: BorgChassisGeneric id: BorgChassisGeneric
parent: BaseBorgChassis parent: BaseBorgChassisNT
components: components:
- type: Sprite - type: Sprite
layers: layers:
@@ -25,7 +25,7 @@
- type: entity - type: entity
id: BorgChassisMining id: BorgChassisMining
parent: BaseBorgChassis parent: BaseBorgChassisNT
name: salvage cyborg name: salvage cyborg
components: components:
- type: Sprite - type: Sprite
@@ -52,7 +52,7 @@
- type: entity - type: entity
id: BorgChassisEngineer id: BorgChassisEngineer
parent: BaseBorgChassis parent: BaseBorgChassisNT
name: engineer cyborg name: engineer cyborg
components: components:
- type: Sprite - type: Sprite
@@ -79,7 +79,7 @@
- type: entity - type: entity
id: BorgChassisJanitor id: BorgChassisJanitor
parent: BaseBorgChassis parent: BaseBorgChassisNT
name: janitor cyborg name: janitor cyborg
components: components:
- type: Sprite - type: Sprite
@@ -106,7 +106,7 @@
- type: entity - type: entity
id: BorgChassisMedical id: BorgChassisMedical
parent: BaseBorgChassis parent: BaseBorgChassisNT
name: medical cyborg name: medical cyborg
components: components:
- type: Sprite - type: Sprite
@@ -133,7 +133,7 @@
- type: entity - type: entity
id: BorgChassisService id: BorgChassisService
parent: BaseBorgChassis parent: BaseBorgChassisNT
name: service cyborg name: service cyborg
components: components:
- type: Sprite - type: Sprite

View File

@@ -2,6 +2,7 @@
save: false save: false
name: BaseMob name: BaseMob
id: BaseMob id: BaseMob
abstract: true
components: components:
- type: CombatMode - type: CombatMode
canDisarm: true canDisarm: true

View File

@@ -244,14 +244,31 @@
- type: entity - type: entity
id: PlayerBorgGeneric id: PlayerBorgGeneric
parent: BorgChassisGeneric parent: BorgChassisGeneric
noSpawn: true suffix: Battery, Tools
components: components:
- type: BorgChassis - type: ContainerFill
startingBrain: MMIFilled containers:
startingModules: borg_brain:
- MMIFilled
borg_module:
- BorgModuleTool - BorgModuleTool
- type: ItemSlots - type: ItemSlots
slots: slots:
cell_slot: cell_slot:
name: power-cell-slot-component-slot-name-default name: power-cell-slot-component-slot-name-default
startingItem: PowerCellMedium startingItem: PowerCellMedium
- type: entity
id: PlayerBorgBattery
parent: BorgChassisGeneric
suffix: Battery
components:
- type: ContainerFill
containers:
borg_brain:
- MMIFilled
- type: ItemSlots
slots:
cell_slot:
name: power-cell-slot-component-slot-name-default
startingItem: PowerCellMedium

View File

@@ -46,8 +46,12 @@
stopSearchVerbPopup: pai-system-stopped-searching stopSearchVerbPopup: pai-system-stopped-searching
- type: Examiner - type: Examiner
- type: IntrinsicRadioReceiver - type: IntrinsicRadioReceiver
- type: IntrinsicRadioTransmitter
channels:
- Binary
- type: ActiveRadio - type: ActiveRadio
channels: channels:
- Binary
- Common - Common
- type: DoAfter - type: DoAfter
- type: Actions - type: Actions

View File

@@ -5,11 +5,6 @@
components: components:
- type: Clickable - type: Clickable
- type: InteractionOutline - type: InteractionOutline
- type: Transform
noRot: true
- type: CollisionWake
- type: TileFrictionModifier
modifier: 0.5
- type: Physics - type: Physics
bodyType: Dynamic bodyType: Dynamic
fixedRotation: false fixedRotation: false

View File

@@ -24,8 +24,8 @@
- Binary - Binary
- type: ActiveRadio - type: ActiveRadio
channels: channels:
- Common
- Binary - Binary
- Common
- type: NameIdentifier - type: NameIdentifier
group: MMI group: MMI
- type: DoAfter - type: DoAfter
@@ -93,8 +93,8 @@
- Binary - Binary
- type: ActiveRadio - type: ActiveRadio
channels: channels:
- Common
- Binary - Binary
- Common
- type: NameIdentifier - type: NameIdentifier
group: PositronicBrain group: PositronicBrain
- type: DoAfter - type: DoAfter

View File

@@ -0,0 +1,6 @@
- type: antag
id: SubvertedSilicon
name: roles-antag-subverted-silicon-name
antagonist: true
setPreference: false
objective: roles-antag-subverted-silicon-objective

View File

@@ -13,8 +13,8 @@
color: "#9FED58" color: "#9FED58"
roles: roles:
- Bartender - Bartender
- Botanist
- Borg - Borg
- Botanist
- Boxer - Boxer
- Chaplain - Chaplain
- Chef - Chef