diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs index ea5aa3cf25..2dbe923b2a 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs @@ -18,15 +18,6 @@ public override Control GetUIFragmentRoot() public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new CrimeAssistUiFragment(); - - _fragment.OnSync += _ => SendSyncMessage(userInterface); - } - - private void SendSyncMessage(BoundUserInterface userInterface) - { - var syncMessage = new CrimeAssistSyncMessageEvent(); - var message = new CartridgeUiMessage(syncMessage); - userInterface.SendMessage(message); } public override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs index e3163975d1..fb085a8a79 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs @@ -1,7 +1,6 @@ using Content.Client.Message; using Content.Shared.DeltaV.CartridgeLoader.Cartridges; using Robust.Client.AutoGenerated; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; @@ -13,9 +12,7 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; public sealed partial class CrimeAssistUiFragment : BoxContainer { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IResourceCache _resourceCache = default!; - public event Action? OnSync; private CrimeAssistPage _currentPage; private List? _pages; diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml new file mode 100644 index 0000000000..2de8a37ff7 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs new file mode 100644 index 0000000000..e8dd4eea44 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs @@ -0,0 +1,21 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchEntryControl : BoxContainer +{ + public SecWatchEntryControl(SecWatchEntry entry) + { + RobustXamlLoader.Load(this); + + Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}"); + Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job)); + + Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason"); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs new file mode 100644 index 0000000000..da5ff825b9 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs @@ -0,0 +1,27 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +public sealed partial class SecWatchUi : UIFragment +{ + private SecWatchUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface ui, EntityUid? owner) + { + _fragment = new SecWatchUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is SecWatchUiState cast) + _fragment?.UpdateState(cast); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml new file mode 100644 index 0000000000..7fb2c42deb --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml @@ -0,0 +1,13 @@ + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs new file mode 100644 index 0000000000..ad15284052 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs @@ -0,0 +1,25 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchUiFragment : BoxContainer +{ + public SecWatchUiFragment() + { + RobustXamlLoader.Load(this); + } + + public void UpdateState(SecWatchUiState state) + { + NoEntries.Visible = state.Entries.Count == 0; + Entries.RemoveAllChildren(); + foreach (var entry in state.Entries) + { + Entries.AddChild(new SecWatchEntryControl(entry)); + } + } +} diff --git a/Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs b/Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs new file mode 100644 index 0000000000..1700796ede --- /dev/null +++ b/Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs @@ -0,0 +1,46 @@ +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; +using Robust.Client.GameObjects; +using Robust.Shared.Timing; + +namespace Content.Client.Movement.Systems; + +/// +/// Controls the switching of motion and standing still animation +/// +public sealed class ClientSpriteMovementSystem : SharedSpriteMovementSystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + + private EntityQuery _spriteQuery; + + public override void Initialize() + { + base.Initialize(); + + _spriteQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnAfterAutoHandleState); + } + + private void OnAfterAutoHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (!_spriteQuery.TryGetComponent(ent, out var sprite)) + return; + + if (ent.Comp.IsMoving) + { + foreach (var (layer, state) in ent.Comp.MovementLayers) + { + sprite.LayerSetData(layer, state); + } + } + else + { + foreach (var (layer, state) in ent.Comp.NoMovementLayers) + { + sprite.LayerSetData(layer, state); + } + } + } +} diff --git a/Content.Client/Movement/Systems/SpriteMovementSystem.cs b/Content.Client/Movement/Systems/SpriteMovementSystem.cs deleted file mode 100644 index 313683855d..0000000000 --- a/Content.Client/Movement/Systems/SpriteMovementSystem.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Content.Shared.Movement.Components; -using Content.Shared.Movement.Events; -using Content.Shared.Movement.Systems; -using Robust.Client.GameObjects; -using Robust.Shared.Timing; - -namespace Content.Client.Movement.Systems; - -/// -/// Handles setting sprite states based on whether an entity has movement input. -/// -public sealed class SpriteMovementSystem : EntitySystem -{ - [Dependency] private readonly IGameTiming _timing = default!; - - private EntityQuery _spriteQuery; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnSpriteMoveInput); - _spriteQuery = GetEntityQuery(); - } - - private void OnSpriteMoveInput(EntityUid uid, SpriteMovementComponent component, ref MoveInputEvent args) - { - if (!_timing.IsFirstTimePredicted) - return; - - var oldMoving = (SharedMoverController.GetNormalizedMovement(args.OldMovement) & MoveButtons.AnyDirection) != MoveButtons.None; - var moving = (SharedMoverController.GetNormalizedMovement(args.Component.HeldMoveButtons) & MoveButtons.AnyDirection) != MoveButtons.None; - - if (oldMoving == moving || !_spriteQuery.TryGetComponent(uid, out var sprite)) - return; - - if (moving) - { - foreach (var (layer, state) in component.MovementLayers) - { - sprite.LayerSetData(layer, state); - } - } - else - { - foreach (var (layer, state) in component.NoMovementLayers) - { - sprite.LayerSetData(layer, state); - } - } - } -} diff --git a/Content.Client/Physics/Controllers/MoverController.cs b/Content.Client/Physics/Controllers/MoverController.cs index 9d453e5518..edd4ef1426 100644 --- a/Content.Client/Physics/Controllers/MoverController.cs +++ b/Content.Client/Physics/Controllers/MoverController.cs @@ -34,57 +34,57 @@ public override void Initialize() Subs.CVar(_config, CCVars.DefaultWalk, _ => RaiseNetworkEvent(new UpdateInputCVarsMessage())); } - private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args) + private void OnUpdatePredicted(Entity entity, ref UpdateIsPredictedEvent args) { // Enable prediction if an entity is controlled by the player - if (uid == _playerManager.LocalEntity) + if (entity.Owner == _playerManager.LocalEntity) args.IsPredicted = true; } - private void OnUpdateRelayTargetPredicted(EntityUid uid, MovementRelayTargetComponent component, ref UpdateIsPredictedEvent args) + private void OnUpdateRelayTargetPredicted(Entity entity, ref UpdateIsPredictedEvent args) { - if (component.Source == _playerManager.LocalEntity) + if (entity.Comp.Source == _playerManager.LocalEntity) args.IsPredicted = true; } - private void OnUpdatePullablePredicted(EntityUid uid, PullableComponent component, ref UpdateIsPredictedEvent args) + private void OnUpdatePullablePredicted(Entity entity, ref UpdateIsPredictedEvent args) { // Enable prediction if an entity is being pulled by the player. // Disable prediction if an entity is being pulled by some non-player entity. - if (component.Puller == _playerManager.LocalEntity) + if (entity.Comp.Puller == _playerManager.LocalEntity) args.IsPredicted = true; - else if (component.Puller != null) + else if (entity.Comp.Puller != null) args.BlockPrediction = true; // TODO recursive pulling checks? // What if the entity is being pulled by a vehicle controlled by the player? } - private void OnRelayPlayerAttached(EntityUid uid, RelayInputMoverComponent component, LocalPlayerAttachedEvent args) + private void OnRelayPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) { - Physics.UpdateIsPredicted(uid); - Physics.UpdateIsPredicted(component.RelayEntity); - if (MoverQuery.TryGetComponent(component.RelayEntity, out var inputMover)) - SetMoveInput(inputMover, MoveButtons.None); + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Owner, inputMover), MoveButtons.None); } - private void OnRelayPlayerDetached(EntityUid uid, RelayInputMoverComponent component, LocalPlayerDetachedEvent args) + private void OnRelayPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) { - Physics.UpdateIsPredicted(uid); - Physics.UpdateIsPredicted(component.RelayEntity); - if (MoverQuery.TryGetComponent(component.RelayEntity, out var inputMover)) - SetMoveInput(inputMover, MoveButtons.None); + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Owner, inputMover), MoveButtons.None); } - private void OnPlayerAttached(EntityUid uid, InputMoverComponent component, LocalPlayerAttachedEvent args) + private void OnPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) { - SetMoveInput(component, MoveButtons.None); + SetMoveInput(entity, MoveButtons.None); } - private void OnPlayerDetached(EntityUid uid, InputMoverComponent component, LocalPlayerDetachedEvent args) + private void OnPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) { - SetMoveInput(component, MoveButtons.None); + SetMoveInput(entity, MoveButtons.None); } public override void UpdateBeforeSolve(bool prediction, float frameTime) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index eccc548297..2eaa9cc130 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -206,8 +206,7 @@ public WiresMenu() (_statusContainer = new GridContainer { Margin = new Thickness(8, 4), - // TODO: automatically change columns count. - Columns = 3 + Rows = 2 }) } } @@ -227,7 +226,8 @@ public WiresMenu() PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")} }); CloseButton.OnPressed += _ => Close(); - SetSize = new Vector2(320, 200); + SetHeight = 200; + MinWidth = 320; } @@ -503,6 +503,8 @@ private sealed class StatusLight : Control public StatusLight(StatusLightData data, IResourceCache resourceCache) { + HorizontalAlignment = HAlignment.Right; + var hsv = Color.ToHsv(data.Color); hsv.Z /= 2; var dimColor = Color.FromHsv(hsv); diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index 2cb34c833c..f2249a4d9a 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -40,7 +40,7 @@ public override void Initialize() private void OnRelayMoveInput(Entity ent, ref MoveInputEvent args) { // If they haven't actually moved then ignore it. - if ((args.Component.HeldMoveButtons & + if ((args.Entity.Comp.HeldMoveButtons & (MoveButtons.Down | MoveButtons.Left | MoveButtons.Up | MoveButtons.Right)) == 0x0) { return; diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index db732d0046..6f1cacd5e1 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -191,9 +191,7 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com } } - _idCardSystem.TryFindIdCard(player, out var idCard); - // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract - order.SetApproverData(idCard.Comp?.FullName, idCard.Comp?.JobTitle); + order.Approved = true; _audio.PlayPvs(component.ConfirmSound, uid); if (!HasComp(uid)) @@ -430,6 +428,7 @@ Entity stationData // Approve it now order.SetApproverData(dest, sender); + order.Approved = true; // Log order addition _adminLogger.Add(LogType.Action, LogImpact.Low, diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs new file mode 100644 index 0000000000..7ccc90ef79 --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Security; + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))] +public sealed partial class SecWatchCartridgeComponent : Component +{ + /// + /// Only show people with these statuses. + /// + [DataField] + public List Statuses = new() + { + SecurityStatus.Suspected, + SecurityStatus.Wanted + }; + + /// + /// Station entity thats getting its records checked. + /// + [DataField] + public EntityUid? Station; +} diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs new file mode 100644 index 0000000000..16da24514c --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs @@ -0,0 +1,73 @@ +using Content.Server.Station.Systems; +using Content.Server.StationRecords; +using Content.Server.StationRecords.Systems; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Content.Shared.CriminalRecords; +using Content.Shared.StationRecords; + +namespace Content.Server.CartridgeLoader.Cartridges; + +public sealed class SecWatchCartridgeSystem : EntitySystem +{ + [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; + [Dependency] private readonly StationRecordsSystem _records = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRecordModified); + + SubscribeLocalEvent(OnUiReady); + } + + private void OnRecordModified(RecordModifiedEvent args) + { + // when a record is modified update the ui of every loaded cartridge tuned to the same station + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var cartridge)) + { + if (cartridge.LoaderUid is not {} loader || comp.Station != args.Station) + continue; + + UpdateUI((uid, comp), loader); + } + } + + private void OnUiReady(Entity ent, ref CartridgeUiReadyEvent args) + { + UpdateUI(ent, args.Loader); + } + + private void UpdateUI(Entity ent, EntityUid loader) + { + // if the loader is on a grid, update the station + // if it is off grid use the cached station + if (_station.GetOwningStation(loader) is {} station) + ent.Comp.Station = station; + + if (!TryComp(ent.Comp.Station, out var records)) + return; + + station = ent.Comp.Station.Value; + + var entries = new List(); + foreach (var (id, criminal) in _records.GetRecordsOfType(station, records)) + { + if (!ent.Comp.Statuses.Contains(criminal.Status)) + continue; + + var key = new StationRecordKey(id, station); + if (!_records.TryGetRecord(key, out var general, records)) + continue; + + var status = criminal.Status; + entries.Add(new SecWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); + } + + var state = new SecWatchUiState(entries); + _cartridgeLoader.UpdateCartridgeUiState(loader, state); + } +} diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs deleted file mode 100644 index 741a613458..0000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -[RegisterComponent] -public sealed partial class CrimeAssistCartridgeComponent : Component -{ } diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs deleted file mode 100644 index 06732c2c53..0000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Content.Server.DeltaV.CartridgeLoader; -using Content.Server.CartridgeLoader.Cartridges; -using Content.Server.CartridgeLoader; - -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -public sealed class CrimeAssistCartridgeSystem : EntitySystem -{ - [Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!; - - public override void Initialize() - { - base.Initialize(); - } -} diff --git a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs b/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs index 3a68fffbcc..186da57e5d 100644 --- a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs +++ b/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs @@ -102,6 +102,13 @@ public enum DeviceNetIdDefaults [DataField("sendBroadcastAttemptEvent")] public bool SendBroadcastAttemptEvent = false; + /// + /// Whether this device's address can be saved to device-lists + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("savableAddress")] + public bool SavableAddress = true; + /// /// A list of device-lists that this device is on. /// diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index 3460124158..31613ca380 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -111,6 +111,13 @@ private void TryAddNetworkDevice(EntityUid configuratorUid, EntityUid? targetUid if (!targetUid.HasValue || !Resolve(targetUid.Value, ref device, false)) return; + //This checks if the device is marked as having a savable address, + //to avoid adding pdas and whatnot to air alarms. This flag is true + //by default, so this will only prevent devices from being added to + //network configurator lists if manually set to false in the prototype + if (!device.SavableAddress) + return; + var address = device.Address; if (string.IsNullOrEmpty(address)) { diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 43b7b6f5f8..261dabcfed 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -127,7 +127,7 @@ private void OnActionPerform(EntityUid uid, GhostComponent component, BooActionE private void OnRelayMoveInput(EntityUid uid, GhostOnMoveComponent component, ref MoveInputEvent args) { // If they haven't actually moved then ignore it. - if ((args.Component.HeldMoveButtons & + if ((args.Entity.Comp.HeldMoveButtons & (MoveButtons.Down | MoveButtons.Left | MoveButtons.Up | MoveButtons.Right)) == 0x0) { return; diff --git a/Content.Server/Movement/Systems/SpriteMovementSystem.cs b/Content.Server/Movement/Systems/SpriteMovementSystem.cs new file mode 100644 index 0000000000..9fc4d82859 --- /dev/null +++ b/Content.Server/Movement/Systems/SpriteMovementSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Movement.Systems; + +namespace Content.Server.Movement.Systems; + +public sealed class SpriteMovementSystem : SharedSpriteMovementSystem +{ +} diff --git a/Content.Server/NPC/HTN/Preconditions/HandcuffedPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/HandcuffedPrecondition.cs new file mode 100644 index 0000000000..4a56eeb953 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/HandcuffedPrecondition.cs @@ -0,0 +1,26 @@ +using Content.Server.Cuffs; +using Content.Shared.Cuffs.Components; + +namespace Content.Server.NPC.HTN.Preconditions; + +public sealed partial class HandcuffedPrecondition : HTNPrecondition +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField] + public bool ReactOnlyWhenFullyCuffed = true; + + public override bool IsMet(NPCBlackboard blackboard) + { + var cuffable = _entManager.System(); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + + if (!_entManager.TryGetComponent(owner, out var cuffComp)) + return false; + + var target = (owner, cuffComp); + + return cuffable.IsCuffed(target, ReactOnlyWhenFullyCuffed); + } + +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs index 54f422fe67..467ac0d414 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs @@ -1,4 +1,5 @@ -using Content.Shared.Movement.Pulling.Components; +using Content.Shared.ActionBlocker; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Systems; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; @@ -7,6 +8,7 @@ public sealed partial class UnPullOperator : HTNOperator { [Dependency] private readonly IEntityManager _entManager = default!; private PullingSystem _pulling = default!; + private ActionBlockerSystem _actionBlocker = default!; private EntityQuery _pullableQuery; @@ -16,6 +18,7 @@ public sealed partial class UnPullOperator : HTNOperator public override void Initialize(IEntitySystemManager sysManager) { base.Initialize(sysManager); + _actionBlocker = sysManager.GetEntitySystem(); _pulling = sysManager.GetEntitySystem(); _pullableQuery = _entManager.GetEntityQuery(); } @@ -25,7 +28,8 @@ public override void Startup(NPCBlackboard blackboard) base.Startup(blackboard); var owner = blackboard.GetValue(NPCBlackboard.Owner); - _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner); + if (_actionBlocker.CanInteract(owner, owner)) //prevents handcuffed monkeys from pulling etc. + _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs index 116e8fe7c7..b242575a12 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs @@ -1,4 +1,4 @@ -using Content.Server.Buckle.Systems; +using Content.Server.Buckle.Systems; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; @@ -19,7 +19,7 @@ public override void Startup(NPCBlackboard blackboard) { base.Startup(blackboard); var owner = blackboard.GetValue(NPCBlackboard.Owner); - _buckle.Unbuckle(owner, null); + _buckle.TryUnbuckle(owner, owner, false); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index 5f871a6ecf..133ecf1154 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -243,12 +243,20 @@ private bool TrySeek( // Alright just adjust slightly and grab the next node so we don't stop moving for a tick. // TODO: If it's the last node just grab the target instead. targetCoordinates = GetTargetCoordinates(steering); - targetMap = targetCoordinates.ToMap(EntityManager, _transform); + + if (!targetCoordinates.IsValid(EntityManager)) + { + SetDirection(uid, mover, steering, Vector2.Zero); + steering.Status = SteeringStatus.NoPath; + return false; + } + + targetMap = _transform.ToMapCoordinates(targetCoordinates); // Can't make it again. if (ourMap.MapId != targetMap.MapId) { - SetDirection(mover, steering, Vector2.Zero); + SetDirection(uid, mover, steering, Vector2.Zero); steering.Status = SteeringStatus.NoPath; return false; } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index dbe1d4d7ea..3ae9a244f3 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.CombatMode; using Content.Shared.Interaction; using Content.Shared.Movement.Components; +using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Content.Shared.NPC; using Content.Shared.NPC.Components; @@ -207,6 +208,9 @@ public void Unregister(EntityUid uid, NPCSteeringComponent? component = null) if (EntityManager.TryGetComponent(uid, out InputMoverComponent? controller)) { controller.CurTickSprintMovement = Vector2.Zero; + + var ev = new SpriteMoveEvent(false); + RaiseLocalEvent(uid, ref ev); } component.PathfindToken?.Cancel(); @@ -270,7 +274,7 @@ public override void Update(float frameTime) } } - private void SetDirection(InputMoverComponent component, NPCSteeringComponent steering, Vector2 value, bool clear = true) + private void SetDirection(EntityUid uid, InputMoverComponent component, NPCSteeringComponent steering, Vector2 value, bool clear = true) { if (clear && value.Equals(Vector2.Zero)) { @@ -282,6 +286,9 @@ private void SetDirection(InputMoverComponent component, NPCSteeringComponent st component.CurTickSprintMovement = value; component.LastInputTick = _timing.CurTick; component.LastInputSubTick = ushort.MaxValue; + + var ev = new SpriteMoveEvent(true); + RaiseLocalEvent(uid, ref ev); } /// @@ -297,7 +304,7 @@ private void Steer( { if (Deleted(steering.Coordinates.EntityId)) { - SetDirection(mover, steering, Vector2.Zero); + SetDirection(uid, mover, steering, Vector2.Zero); steering.Status = SteeringStatus.NoPath; return; } @@ -305,14 +312,14 @@ private void Steer( // No path set from pathfinding or the likes. if (steering.Status == SteeringStatus.NoPath) { - SetDirection(mover, steering, Vector2.Zero); + SetDirection(uid, mover, steering, Vector2.Zero); return; } // Can't move at all, just noop input. if (!mover.CanMove) { - SetDirection(mover, steering, Vector2.Zero); + SetDirection(uid, mover, steering, Vector2.Zero); steering.Status = SteeringStatus.NoPath; return; } @@ -341,7 +348,7 @@ private void Steer( if (steering.CanSeek && !TrySeek(uid, mover, steering, body, xform, offsetRot, moveSpeed, interest, frameTime, ref forceSteer)) { - SetDirection(mover, steering, Vector2.Zero); + SetDirection(uid, mover, steering, Vector2.Zero); return; } @@ -354,7 +361,7 @@ private void Steer( if (!forceSteer) { - SetDirection(mover, steering, steering.LastSteerDirection, false); + SetDirection(uid, mover, steering, steering.LastSteerDirection, false); return; } @@ -391,7 +398,7 @@ private void Steer( steering.LastSteerDirection = resultDirection; DebugTools.Assert(!float.IsNaN(resultDirection.X)); - SetDirection(mover, steering, resultDirection, false); + SetDirection(uid, mover, steering, resultDirection, false); } private EntityCoordinates GetCoordinates(PathPoly poly) diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index 759b8ef29c..4e61cdcb52 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -30,26 +30,26 @@ public override void Initialize() SubscribeLocalEvent(OnPlayerDetached); } - private void OnRelayPlayerAttached(EntityUid uid, RelayInputMoverComponent component, PlayerAttachedEvent args) + private void OnRelayPlayerAttached(Entity entity, ref PlayerAttachedEvent args) { - if (MoverQuery.TryGetComponent(component.RelayEntity, out var inputMover)) - SetMoveInput(inputMover, MoveButtons.None); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Owner, inputMover), MoveButtons.None); } - private void OnRelayPlayerDetached(EntityUid uid, RelayInputMoverComponent component, PlayerDetachedEvent args) + private void OnRelayPlayerDetached(Entity entity, ref PlayerDetachedEvent args) { - if (MoverQuery.TryGetComponent(component.RelayEntity, out var inputMover)) - SetMoveInput(inputMover, MoveButtons.None); + if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Owner, inputMover), MoveButtons.None); } - private void OnPlayerAttached(EntityUid uid, InputMoverComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(Entity entity, ref PlayerAttachedEvent args) { - SetMoveInput(component, MoveButtons.None); + SetMoveInput(entity, MoveButtons.None); } - private void OnPlayerDetached(EntityUid uid, InputMoverComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(Entity entity, ref PlayerDetachedEvent args) { - SetMoveInput(component, MoveButtons.None); + SetMoveInput(entity, MoveButtons.None); } protected override bool CanSound() diff --git a/Content.Server/PowerCell/PowerCellSystem.Draw.cs b/Content.Server/PowerCell/PowerCellSystem.Draw.cs index 9ebd677f47..ae43b6dae9 100644 --- a/Content.Server/PowerCell/PowerCellSystem.Draw.cs +++ b/Content.Server/PowerCell/PowerCellSystem.Draw.cs @@ -1,5 +1,4 @@ using Content.Server.Power.Components; -using Content.Shared.Item.ItemToggle.Components; using Content.Shared.PowerCell; using Content.Shared.PowerCell.Components; @@ -14,11 +13,11 @@ public sealed partial class PowerCellSystem public override void Update(float frameTime) { base.Update(frameTime); - var query = EntityQueryEnumerator(); + var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var comp, out var slot, out var toggle)) + while (query.MoveNext(out var uid, out var comp, out var slot)) { - if (!comp.Enabled || !toggle.Activated) + if (!comp.Enabled) continue; if (Timing.CurTime < comp.NextUpdateTime) @@ -32,8 +31,6 @@ public override void Update(float frameTime) if (_battery.TryUseCharge(batteryEnt.Value, comp.DrawRate, battery)) continue; - Toggle.TryDeactivate((uid, toggle)); - var ev = new PowerCellSlotEmptyEvent(); RaiseLocalEvent(uid, ref ev); } @@ -60,7 +57,10 @@ private void OnDrawCellChanged(EntityUid uid, PowerCellDrawComponent component, var canUse = !args.Ejected && HasActivatableCharge(uid, component); if (!canDraw) - Toggle.TryDeactivate(uid); + { + var ev = new PowerCellSlotEmptyEvent(); + RaiseLocalEvent(uid, ref ev); + } if (canUse != component.CanUse || canDraw != component.CanDraw) { diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 3ffd1baf5d..25a5f4c96e 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -283,6 +283,7 @@ public void BorgActivate(EntityUid uid, BorgChassisComponent component) { Popup.PopupEntity(Loc.GetString("borg-mind-added", ("name", Identity.Name(uid, EntityManager))), uid); Toggle.TryActivate(uid); + _powerCell.SetDrawEnabled(uid, _mobState.IsAlive(uid)); _appearance.SetData(uid, BorgVisuals.HasPlayer, true); } @@ -293,6 +294,7 @@ public void BorgDeactivate(EntityUid uid, BorgChassisComponent component) { Popup.PopupEntity(Loc.GetString("borg-mind-removed", ("name", Identity.Name(uid, EntityManager))), uid); Toggle.TryDeactivate(uid); + _powerCell.SetDrawEnabled(uid, false); _appearance.SetData(uid, BorgVisuals.HasPlayer, false); } diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs index 5cc3c52be4..5e50740ae6 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs @@ -91,7 +91,7 @@ private void OnComponentStartup(EntityUid uid, SurveillanceCameraMonitorComponen private void OnSubnetRequest(EntityUid uid, SurveillanceCameraMonitorComponent component, SurveillanceCameraMonitorSubnetRequestMessage args) { - if (args.Actor != null) + if (args.Actor is { Valid: true } actor && !Deleted(actor)) { SetActiveSubnet(uid, args.Subnet, component); } @@ -147,6 +147,7 @@ private void OnPacketReceived(EntityUid uid, SurveillanceCameraMonitorComponent break; case SurveillanceCameraSystem.CameraSubnetData: if (args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out string? subnet) + && !string.IsNullOrEmpty(subnet) && !component.KnownSubnets.ContainsKey(subnet)) { component.KnownSubnets.Add(subnet, args.SenderAddress); @@ -218,6 +219,7 @@ private void SendHeartbeat(EntityUid uid, SurveillanceCameraMonitorComponent? mo { if (!Resolve(uid, ref monitor) || monitor.LastHeartbeatSent < _heartbeatDelay + || string.IsNullOrEmpty(monitor.ActiveSubnet) || !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var subnetAddress)) { return; @@ -279,6 +281,7 @@ private void SetActiveSubnet(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null) { if (!Resolve(uid, ref monitor) + || string.IsNullOrEmpty(subnet) || !monitor.KnownSubnets.ContainsKey(subnet)) { return; @@ -296,6 +299,7 @@ private void SetActiveSubnet(EntityUid uid, string subnet, private void RequestActiveSubnetInfo(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null) { if (!Resolve(uid, ref monitor) + || string.IsNullOrEmpty(monitor.ActiveSubnet) || !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var address)) { return; @@ -311,6 +315,7 @@ private void RequestActiveSubnetInfo(EntityUid uid, SurveillanceCameraMonitorCom private void ConnectToSubnet(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null) { if (!Resolve(uid, ref monitor) + || string.IsNullOrEmpty(subnet) || !monitor.KnownSubnets.TryGetValue(subnet, out var address)) { return; @@ -328,6 +333,7 @@ private void ConnectToSubnet(EntityUid uid, string subnet, SurveillanceCameraMon private void DisconnectFromSubnet(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null) { if (!Resolve(uid, ref monitor) + || string.IsNullOrEmpty(subnet) || !monitor.KnownSubnets.TryGetValue(subnet, out var address)) { return; @@ -416,6 +422,7 @@ private void TrySwitchCameraByAddress(EntityUid uid, string address, SurveillanceCameraMonitorComponent? monitor = null) { if (!Resolve(uid, ref monitor) + || string.IsNullOrEmpty(monitor.ActiveSubnet) || !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var subnetAddress)) { return; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs index e44ee6baa1..b1a08fb505 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs @@ -2,6 +2,8 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Shared.Mind.Components; using Content.Shared.Teleportation.Systems; +using Robust.Shared.Collections; +using Robust.Shared.Containers; using Robust.Shared.Random; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; @@ -11,6 +13,7 @@ public sealed class PortalArtifactSystem : EntitySystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly LinkedEntitySystem _link = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; public override void Initialize() { @@ -21,21 +24,28 @@ public override void Initialize() private void OnActivate(Entity artifact, ref ArtifactActivatedEvent args) { var map = Transform(artifact).MapID; - var firstPortal = Spawn(artifact.Comp.PortalProto, _transform.GetMapCoordinates(artifact)); - - var minds = new List(); - var mindQuery = EntityQueryEnumerator(); - while (mindQuery.MoveNext(out var uid, out var mc, out var xform)) + var validMinds = new ValueList(); + var mindQuery = EntityQueryEnumerator(); + while (mindQuery.MoveNext(out var uid, out var mc, out var xform, out var meta)) { - if (mc.HasMind && xform.MapID == map) - minds.Add(uid); + // check if the MindContainer has a Mind and if the entity is not in a container (this also auto excludes AI) and if they are on the same map + if (mc.HasMind && !_container.IsEntityOrParentInContainer(uid, meta: meta, xform: xform) && xform.MapID == map) + { + validMinds.Add(uid); + } } + //this would only be 0 if there were a station full of AIs and no one else, in that case just stop this function + if (validMinds.Count == 0) + return; + + var firstPortal = Spawn(artifact.Comp.PortalProto, _transform.GetMapCoordinates(artifact)); + + var target = _random.Pick(validMinds); - var target = _random.Pick(minds); var secondPortal = Spawn(artifact.Comp.PortalProto, _transform.GetMapCoordinates(target)); //Manual position swapping, because the portal that opens doesn't trigger a collision, and doesn't teleport targets the first time. - _transform.SwapPositions(target, secondPortal); + _transform.SwapPositions(target, artifact.Owner); _link.TryLink(firstPortal, secondPortal, true); } diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index 7a79070bd8..c031902b6e 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -239,7 +239,7 @@ private void UpdateEntityName(EntityUid uid, IdCardComponent? id = null) private static string ExtractFullTitle(IdCardComponent idCardComponent) { - return $"{idCardComponent.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(idCardComponent.JobTitle ?? string.Empty)})" + return $"{idCardComponent.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(idCardComponent.LocalizedJobTitle ?? string.Empty)})" .Trim(); } } diff --git a/Content.Shared/Cargo/CargoOrderData.cs b/Content.Shared/Cargo/CargoOrderData.cs index 7b3490630e..76954780ed 100644 --- a/Content.Shared/Cargo/CargoOrderData.cs +++ b/Content.Shared/Cargo/CargoOrderData.cs @@ -48,7 +48,7 @@ public sealed partial class CargoOrderData // public int RequesterId; [DataField] public string Reason { get; private set; } - public bool Approved => Approver is not null; + public bool Approved; [DataField] public string? Approver; diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index 8dbed2fa44..9269f7d179 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -212,7 +212,7 @@ private void OnBuckleAttempt(Entity ent, EntityUid? user, ref if (cancelled || user != ent.Owner) return; - if (!TryComp(ent, out var hands) || ent.Comp.CuffedHandCount != hands.Count) + if (!TryComp(ent, out var hands) || ent.Comp.CuffedHandCount < hands.Count) return; cancelled = true; @@ -548,6 +548,25 @@ public bool TryCuffing(EntityUid user, EntityUid target, EntityUid handcuff, Han return true; } + /// + /// Checks if the target is handcuffed. + /// + /// when true, return false if the target is only partially cuffed (for things with more than 2 hands) + /// + public bool IsCuffed(Entity target, bool requireFullyCuffed = true) + { + if (!TryComp(target, out var hands)) + return false; + + if (target.Comp.CuffedHandCount <= 0) + return false; + + if (requireFullyCuffed && hands.Count > target.Comp.CuffedHandCount) + return false; + + return true; + } + /// /// Attempt to uncuff a cuffed entity. Can be called by the cuffed entity, or another entity trying to help uncuff them. /// If the uncuffing succeeds, the cuffs will drop on the floor. diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs deleted file mode 100644 index dd820f1a0b..0000000000 --- a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Robust.Shared.Serialization; - -namespace Content.Shared.DeltaV.CartridgeLoader.Cartridges; - -[Serializable, NetSerializable] -public sealed class CrimeAssistUiState : BoundUserInterfaceState -{ - public CrimeAssistUiState() - { } -} - -[Serializable, NetSerializable] -public sealed class CrimeAssistSyncMessageEvent : CartridgeMessageEvent -{ - public CrimeAssistSyncMessageEvent() - { } -} diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs new file mode 100644 index 0000000000..068b54a6ff --- /dev/null +++ b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs @@ -0,0 +1,24 @@ +using Content.Shared.Security; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +/// +/// Show a list of wanted and suspected people from criminal records. +/// +[Serializable, NetSerializable] +public sealed class SecWatchUiState : BoundUserInterfaceState +{ + public readonly List Entries; + + public SecWatchUiState(List entries) + { + Entries = entries; + } +} + +/// +/// Entry for a person who is wanted or suspected. +/// +[Serializable, NetSerializable] +public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason); diff --git a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs index e7a88b6ef2..af0de0eb2b 100644 --- a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs +++ b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs @@ -21,7 +21,8 @@ public enum IdentityBlockerCoverage NONE = 0, MOUTH = 1 << 0, EYES = 1 << 1, - FULL = MOUTH | EYES + OUTER = 1 << 2, + FULL = MOUTH | EYES | OUTER } /// @@ -30,7 +31,7 @@ public enum IdentityBlockerCoverage public sealed class SeeIdentityAttemptEvent : CancellableEntityEventArgs, IInventoryRelayEvent { // i.e. masks, helmets, or glasses. - public SlotFlags TargetSlots => SlotFlags.MASK | SlotFlags.HEAD | SlotFlags.EYES; + public SlotFlags TargetSlots => SlotFlags.MASK | SlotFlags.HEAD | SlotFlags.EYES | SlotFlags.OUTERCLOTHING; // cumulative coverage from each relayed slot public IdentityBlockerCoverage TotalCoverage = IdentityBlockerCoverage.NONE; diff --git a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs index 044a1109a1..ece56b687c 100644 --- a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs +++ b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs @@ -27,10 +27,14 @@ public sealed class ItemToggleSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + private EntityQuery _query; + public override void Initialize() { base.Initialize(); + _query = GetEntityQuery(); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(TurnOffOnUnwielded); @@ -103,7 +107,7 @@ private void OnActivate(Entity ent, ref ActivateInWorldEven /// Same as public bool Toggle(Entity ent, EntityUid? user = null, bool predicted = true) { - if (!Resolve(ent, ref ent.Comp)) + if (!_query.Resolve(ent, ref ent.Comp, false)) return false; return TrySetActive(ent, !ent.Comp.Activated, user, predicted); @@ -126,7 +130,7 @@ public bool TrySetActive(Entity ent, bool active, EntityUi /// public bool TryActivate(Entity ent, EntityUid? user = null, bool predicted = true) { - if (!Resolve(ent, ref ent.Comp)) + if (!_query.Resolve(ent, ref ent.Comp, false)) return false; var uid = ent.Owner; @@ -169,7 +173,7 @@ public bool TryActivate(Entity ent, EntityUid? user = null /// public bool TryDeactivate(Entity ent, EntityUid? user = null, bool predicted = true) { - if (!Resolve(ent, ref ent.Comp)) + if (!_query.Resolve(ent, ref ent.Comp, false)) return false; var uid = ent.Owner; @@ -255,7 +259,7 @@ private void TurnOnOnWielded(Entity ent, ref ItemWieldedEve public bool IsActivated(Entity ent) { - if (!Resolve(ent, ref ent.Comp, false)) + if (!_query.Resolve(ent, ref ent.Comp, false)) return true; // assume always activated if no component return ent.Comp.Activated; diff --git a/Content.Shared/Movement/Components/SpriteMovementComponent.cs b/Content.Shared/Movement/Components/SpriteMovementComponent.cs index 8dd058f154..b5a9e37352 100644 --- a/Content.Shared/Movement/Components/SpriteMovementComponent.cs +++ b/Content.Shared/Movement/Components/SpriteMovementComponent.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Movement.Components; /// /// Updates a sprite layer based on whether an entity is moving via input or not. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class SpriteMovementComponent : Component { /// @@ -19,4 +19,7 @@ public sealed partial class SpriteMovementComponent : Component /// [DataField] public Dictionary NoMovementLayers = new(); + + [DataField, AutoNetworkedField] + public bool IsMoving; } diff --git a/Content.Shared/Movement/Events/MoveInputEvent.cs b/Content.Shared/Movement/Events/MoveInputEvent.cs index 1c677a42e8..9c49da722c 100644 --- a/Content.Shared/Movement/Events/MoveInputEvent.cs +++ b/Content.Shared/Movement/Events/MoveInputEvent.cs @@ -9,16 +9,14 @@ namespace Content.Shared.Movement.Events; [ByRefEvent] public readonly struct MoveInputEvent { - public readonly EntityUid Entity; - public readonly InputMoverComponent Component; + public readonly Entity Entity; public readonly MoveButtons OldMovement; - public bool HasDirectionalMovement => (Component.HeldMoveButtons & MoveButtons.AnyDirection) != MoveButtons.None; + public bool HasDirectionalMovement => (Entity.Comp.HeldMoveButtons & MoveButtons.AnyDirection) != MoveButtons.None; - public MoveInputEvent(EntityUid entity, InputMoverComponent component, MoveButtons oldMovement) + public MoveInputEvent(Entity entity, MoveButtons oldMovement) { Entity = entity; - Component = component; OldMovement = oldMovement; } } diff --git a/Content.Shared/Movement/Events/SpriteMoveEvent.cs b/Content.Shared/Movement/Events/SpriteMoveEvent.cs new file mode 100644 index 0000000000..25ebffe2df --- /dev/null +++ b/Content.Shared/Movement/Events/SpriteMoveEvent.cs @@ -0,0 +1,15 @@ +namespace Content.Shared.Movement.Events; + +/// +/// Raised on an entity whenever it should change movement sprite +/// +[ByRefEvent] +public readonly struct SpriteMoveEvent +{ + public readonly bool IsMoving = false; + + public SpriteMoveEvent(bool isMoving) + { + IsMoving = isMoving; + } +} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs b/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs index 97c837eb8e..4228b77847 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.CVars.cs @@ -23,7 +23,7 @@ private void OnMindAdded(Entity ent, ref MindAddedMessage a return; ent.Comp.DefaultSprinting = _netConfig.GetClientCVar(channel, CCVars.DefaultWalk); - WalkingAlert(ent, ent.Comp); + WalkingAlert(ent); } private void OnMindRemoved(Entity ent, ref MindRemovedMessage args) @@ -38,6 +38,6 @@ private void OnUpdateCVars(UpdateInputCVarsMessage msg, EntitySessionEventArgs a return; mover.DefaultSprinting = _netConfig.GetClientCVar(args.SenderSession.Channel, CCVars.DefaultWalk); - WalkingAlert(uid, mover); + WalkingAlert((uid, mover)); } } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index 2ea6015557..bb6951f2de 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -85,55 +85,61 @@ public static MoveButtons GetNormalizedMovement(MoveButtons buttons) return oldMovement; } - protected void SetMoveInput(InputMoverComponent component, MoveButtons buttons) + protected void SetMoveInput(Entity entity, MoveButtons buttons) { - if (component.HeldMoveButtons == buttons) + if (entity.Comp.HeldMoveButtons == buttons) return; // Relay the fact we had any movement event. // TODO: Ideally we'd do these in a tick instead of out of sim. - var moveEvent = new MoveInputEvent(component.Owner, component, component.HeldMoveButtons); - component.HeldMoveButtons = buttons; - RaiseLocalEvent(component.Owner, ref moveEvent); - Dirty(component.Owner, component); + var moveEvent = new MoveInputEvent(entity, entity.Comp.HeldMoveButtons); + entity.Comp.HeldMoveButtons = buttons; + RaiseLocalEvent(entity, ref moveEvent); + Dirty(entity, entity.Comp); + + var ev = new SpriteMoveEvent(entity.Comp.HeldMoveButtons != MoveButtons.None); + RaiseLocalEvent(entity, ref ev); } - private void OnMoverHandleState(EntityUid uid, InputMoverComponent component, ComponentHandleState args) + private void OnMoverHandleState(Entity entity, ref ComponentHandleState args) { if (args.Current is not InputMoverComponentState state) return; // Handle state - component.LerpTarget = state.LerpTarget; - component.RelativeRotation = state.RelativeRotation; - component.TargetRelativeRotation = state.TargetRelativeRotation; - component.CanMove = state.CanMove; - component.RelativeEntity = EnsureEntity(state.RelativeEntity, uid); - component.DefaultSprinting = state.DefaultSprinting; + entity.Comp.LerpTarget = state.LerpTarget; + entity.Comp.RelativeRotation = state.RelativeRotation; + entity.Comp.TargetRelativeRotation = state.TargetRelativeRotation; + entity.Comp.CanMove = state.CanMove; + entity.Comp.RelativeEntity = EnsureEntity(state.RelativeEntity, entity.Owner); + entity.Comp.DefaultSprinting = state.DefaultSprinting; // Reset - component.LastInputTick = GameTick.Zero; - component.LastInputSubTick = 0; + entity.Comp.LastInputTick = GameTick.Zero; + entity.Comp.LastInputSubTick = 0; - if (component.HeldMoveButtons != state.HeldMoveButtons) + if (entity.Comp.HeldMoveButtons != state.HeldMoveButtons) { - var moveEvent = new MoveInputEvent(uid, component, component.HeldMoveButtons); - component.HeldMoveButtons = state.HeldMoveButtons; - RaiseLocalEvent(uid, ref moveEvent); + var moveEvent = new MoveInputEvent(entity, entity.Comp.HeldMoveButtons); + entity.Comp.HeldMoveButtons = state.HeldMoveButtons; + RaiseLocalEvent(entity.Owner, ref moveEvent); + + var ev = new SpriteMoveEvent(entity.Comp.HeldMoveButtons != MoveButtons.None); + RaiseLocalEvent(entity, ref ev); } } - private void OnMoverGetState(EntityUid uid, InputMoverComponent component, ref ComponentGetState args) + private void OnMoverGetState(Entity entity, ref ComponentGetState args) { args.State = new InputMoverComponentState() { - CanMove = component.CanMove, - RelativeEntity = GetNetEntity(component.RelativeEntity), - LerpTarget = component.LerpTarget, - HeldMoveButtons = component.HeldMoveButtons, - RelativeRotation = component.RelativeRotation, - TargetRelativeRotation = component.TargetRelativeRotation, - DefaultSprinting = component.DefaultSprinting + CanMove = entity.Comp.CanMove, + RelativeEntity = GetNetEntity(entity.Comp.RelativeEntity), + LerpTarget = entity.Comp.LerpTarget, + HeldMoveButtons = entity.Comp.HeldMoveButtons, + RelativeRotation = entity.Comp.RelativeRotation, + TargetRelativeRotation = entity.Comp.TargetRelativeRotation, + DefaultSprinting = entity.Comp.DefaultSprinting }; } @@ -146,9 +152,9 @@ private void ShutdownInput() protected virtual void HandleShuttleInput(EntityUid uid, ShuttleButtons button, ushort subTick, bool state) {} - private void OnAutoParentChange(EntityUid uid, AutoOrientComponent component, ref EntParentChangedMessage args) + private void OnAutoParentChange(Entity entity, ref EntParentChangedMessage args) { - ResetCamera(uid); + ResetCamera(entity.Owner); } public void RotateCamera(EntityUid uid, Angle angle) @@ -237,28 +243,28 @@ public Angle GetParentGridAngle(InputMoverComponent mover) return rotation; } - private void OnFollowedParentChange(EntityUid uid, FollowedComponent component, ref EntParentChangedMessage args) + private void OnFollowedParentChange(Entity entity, ref EntParentChangedMessage args) { - foreach (var foll in component.Following) + foreach (var foll in entity.Comp.Following) { if (!MoverQuery.TryGetComponent(foll, out var mover)) continue; var ev = new EntParentChangedMessage(foll, null, args.OldMapId, XformQuery.GetComponent(foll)); - OnInputParentChange(foll, mover, ref ev); + OnInputParentChange((foll, mover), ref ev); } } - private void OnInputParentChange(EntityUid uid, InputMoverComponent component, ref EntParentChangedMessage args) + private void OnInputParentChange(Entity entity, ref EntParentChangedMessage args) { // If we change our grid / map then delay updating our LastGridAngle. var relative = args.Transform.GridUid; relative ??= args.Transform.MapUid; - if (component.LifeStage < ComponentLifeStage.Running) + if (entity.Comp.LifeStage < ComponentLifeStage.Running) { - component.RelativeEntity = relative; - Dirty(uid, component); + entity.Comp.RelativeEntity = relative; + Dirty(entity.Owner, entity.Comp); return; } @@ -268,28 +274,28 @@ private void OnInputParentChange(EntityUid uid, InputMoverComponent component, r // If we change maps then reset eye rotation entirely. if (oldMapId != mapId) { - component.RelativeEntity = relative; - component.TargetRelativeRotation = Angle.Zero; - component.RelativeRotation = Angle.Zero; - component.LerpTarget = TimeSpan.Zero; - Dirty(uid, component); + entity.Comp.RelativeEntity = relative; + entity.Comp.TargetRelativeRotation = Angle.Zero; + entity.Comp.RelativeRotation = Angle.Zero; + entity.Comp.LerpTarget = TimeSpan.Zero; + Dirty(entity.Owner, entity.Comp); return; } // If we go on a grid and back off then just reset the accumulator. - if (relative == component.RelativeEntity) + if (relative == entity.Comp.RelativeEntity) { - if (component.LerpTarget >= Timing.CurTime) + if (entity.Comp.LerpTarget >= Timing.CurTime) { - component.LerpTarget = TimeSpan.Zero; - Dirty(uid, component); + entity.Comp.LerpTarget = TimeSpan.Zero; + Dirty(entity.Owner, entity.Comp); } return; } - component.LerpTarget = TimeSpan.FromSeconds(InputMoverComponent.LerpTime) + Timing.CurTime; - Dirty(uid, component); + entity.Comp.LerpTarget = TimeSpan.FromSeconds(InputMoverComponent.LerpTime) + Timing.CurTime; + Dirty(entity.Owner, entity.Comp); } private void HandleDirChange(EntityUid entity, Direction dir, ushort subTick, bool state) @@ -303,7 +309,7 @@ private void HandleDirChange(EntityUid entity, Direction dir, ushort subTick, bo DebugTools.AssertNotNull(relayMover.RelayEntity); if (MoverQuery.TryGetComponent(entity, out var mover)) - SetMoveInput(mover, MoveButtons.None); + SetMoveInput((entity, mover), MoveButtons.None); if (_mobState.IsDead(entity) || _mobState.IsCritical(entity) && !_configManager.GetCVar(CCVars.AllowMovementWhileCrit)) @@ -328,19 +334,19 @@ private void HandleDirChange(EntityUid entity, Direction dir, ushort subTick, bo RaiseLocalEvent(xform.ParentUid, ref relayMoveEvent); } - SetVelocityDirection(entity, moverComp, dir, subTick, state); + SetVelocityDirection((entity, moverComp), dir, subTick, state); } - private void OnInputInit(EntityUid uid, InputMoverComponent component, ComponentInit args) + private void OnInputInit(Entity entity, ref ComponentInit args) { - var xform = Transform(uid); + var xform = Transform(entity.Owner); if (!xform.ParentUid.IsValid()) return; - component.RelativeEntity = xform.GridUid ?? xform.MapUid; - component.TargetRelativeRotation = Angle.Zero; - WalkingAlert(uid, component); + entity.Comp.RelativeEntity = xform.GridUid ?? xform.MapUid; + entity.Comp.TargetRelativeRotation = Angle.Zero; + WalkingAlert(entity); } private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) @@ -352,8 +358,8 @@ private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) // if we swap to relay then stop our existing input if we ever change back. if (moverComp != null) { - SetMoveInput(moverComp, MoveButtons.None); - WalkingAlert(uid, moverComp); + SetMoveInput((uid, moverComp), MoveButtons.None); + WalkingAlert((uid, moverComp)); } HandleRunChange(relayMover.RelayEntity, subTick, walking); @@ -362,7 +368,7 @@ private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) if (moverComp == null) return; - SetSprinting(uid, moverComp, subTick, walking); + SetSprinting((uid, moverComp), subTick, walking); } public (Vector2 Walking, Vector2 Sprinting) GetVelocityInput(InputMoverComponent mover) @@ -413,7 +419,7 @@ private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) /// composed into a single direction vector, . Enabling /// opposite directions will cancel each other out, resulting in no direction. /// - public void SetVelocityDirection(EntityUid entity, InputMoverComponent component, Direction direction, ushort subTick, bool enabled) + public void SetVelocityDirection(Entity entity, Direction direction, ushort subTick, bool enabled) { // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] {direction}: {enabled}"); @@ -426,26 +432,26 @@ public void SetVelocityDirection(EntityUid entity, InputMoverComponent component _ => throw new ArgumentException(nameof(direction)) }; - SetMoveInput(entity, component, subTick, enabled, bit); + SetMoveInput(entity, subTick, enabled, bit); } - private void SetMoveInput(EntityUid entity, InputMoverComponent component, ushort subTick, bool enabled, MoveButtons bit) + private void SetMoveInput(Entity entity, ushort subTick, bool enabled, MoveButtons bit) { // Modifies held state of a movement button at a certain sub tick and updates current tick movement vectors. - ResetSubtick(component); + ResetSubtick(entity.Comp); - if (subTick >= component.LastInputSubTick) + if (subTick >= entity.Comp.LastInputSubTick) { - var fraction = (subTick - component.LastInputSubTick) / (float) ushort.MaxValue; + var fraction = (subTick - entity.Comp.LastInputSubTick) / (float) ushort.MaxValue; - ref var lastMoveAmount = ref component.Sprinting ? ref component.CurTickSprintMovement : ref component.CurTickWalkMovement; + ref var lastMoveAmount = ref entity.Comp.Sprinting ? ref entity.Comp.CurTickSprintMovement : ref entity.Comp.CurTickWalkMovement; - lastMoveAmount += DirVecForButtons(component.HeldMoveButtons) * fraction; + lastMoveAmount += DirVecForButtons(entity.Comp.HeldMoveButtons) * fraction; - component.LastInputSubTick = subTick; + entity.Comp.LastInputSubTick = subTick; } - var buttons = component.HeldMoveButtons; + var buttons = entity.Comp.HeldMoveButtons; if (enabled) { @@ -456,7 +462,7 @@ private void SetMoveInput(EntityUid entity, InputMoverComponent component, ushor buttons &= ~bit; } - SetMoveInput(component, buttons); + SetMoveInput(entity, buttons); } private void ResetSubtick(InputMoverComponent component) @@ -469,12 +475,12 @@ private void ResetSubtick(InputMoverComponent component) component.LastInputSubTick = 0; } - - public void SetSprinting(EntityUid entity, InputMoverComponent component, ushort subTick, bool walking) + public void SetSprinting(Entity entity, ushort subTick, bool walking) { // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}"); - SetMoveInput(entity, component, subTick, walking, MoveButtons.Walk); - WalkingAlert(entity, component); + + SetMoveInput(entity, subTick, walking, MoveButtons.Walk); + WalkingAlert(entity); } /// diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs b/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs index 8568290bff..8156955377 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs @@ -12,14 +12,14 @@ private void InitializeRelay() SubscribeLocalEvent(OnAfterRelayState); } - private void OnAfterRelayTargetState(EntityUid uid, MovementRelayTargetComponent component, ref AfterAutoHandleStateEvent args) + private void OnAfterRelayTargetState(Entity entity, ref AfterAutoHandleStateEvent args) { - Physics.UpdateIsPredicted(uid); + Physics.UpdateIsPredicted(entity.Owner); } - private void OnAfterRelayState(EntityUid uid, RelayInputMoverComponent component, ref AfterAutoHandleStateEvent args) + private void OnAfterRelayState(Entity entity, ref AfterAutoHandleStateEvent args) { - Physics.UpdateIsPredicted(uid); + Physics.UpdateIsPredicted(entity.Owner); } /// @@ -61,30 +61,30 @@ public void SetRelay(EntityUid uid, EntityUid relayEntity) Dirty(relayEntity, targetComp); } - private void OnRelayShutdown(EntityUid uid, RelayInputMoverComponent component, ComponentShutdown args) + private void OnRelayShutdown(Entity entity, ref ComponentShutdown args) { - Physics.UpdateIsPredicted(uid); - Physics.UpdateIsPredicted(component.RelayEntity); + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.RelayEntity); - if (TryComp(component.RelayEntity, out var inputMover)) - SetMoveInput(inputMover, MoveButtons.None); + if (TryComp(entity.Comp.RelayEntity, out var inputMover)) + SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); if (Timing.ApplyingState) return; - if (TryComp(component.RelayEntity, out MovementRelayTargetComponent? target) && target.LifeStage <= ComponentLifeStage.Running) - RemComp(component.RelayEntity, target); + if (TryComp(entity.Comp.RelayEntity, out MovementRelayTargetComponent? target) && target.LifeStage <= ComponentLifeStage.Running) + RemComp(entity.Comp.RelayEntity, target); } - private void OnTargetRelayShutdown(EntityUid uid, MovementRelayTargetComponent component, ComponentShutdown args) + private void OnTargetRelayShutdown(Entity entity, ref ComponentShutdown args) { - Physics.UpdateIsPredicted(uid); - Physics.UpdateIsPredicted(component.Source); + Physics.UpdateIsPredicted(entity.Owner); + Physics.UpdateIsPredicted(entity.Comp.Source); if (Timing.ApplyingState) return; - if (TryComp(component.Source, out RelayInputMoverComponent? relay) && relay.LifeStage <= ComponentLifeStage.Running) - RemComp(component.Source, relay); + if (TryComp(entity.Comp.Source, out RelayInputMoverComponent? relay) && relay.LifeStage <= ComponentLifeStage.Running) + RemComp(entity.Comp.Source, relay); } } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 46ee949a4e..701f32f0c7 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -295,9 +295,9 @@ protected void HandleMobMovement( PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent); } - private void WalkingAlert(EntityUid player, InputMoverComponent component) + private void WalkingAlert(Entity entity) { - _alerts.ShowAlert(player, component.WalkingAlert, component.Sprinting ? (short) 1 : (short) 0); + _alerts.ShowAlert(entity, entity.Comp.WalkingAlert, entity.Comp.Sprinting ? (short) 1 : (short) 0); } public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime) diff --git a/Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs b/Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs new file mode 100644 index 0000000000..eb4bbc1be6 --- /dev/null +++ b/Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs @@ -0,0 +1,23 @@ +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Events; + +namespace Content.Shared.Movement.Systems; + +public abstract class SharedSpriteMovementSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnSpriteMoveInput); + } + + private void OnSpriteMoveInput(Entity ent, ref SpriteMoveEvent args) + { + if (ent.Comp.IsMoving == args.IsMoving) + return; + + ent.Comp.IsMoving = args.IsMoving; + Dirty(ent); + } +} diff --git a/Content.Shared/PowerCell/Components/ToggleCellDrawComponent.cs b/Content.Shared/PowerCell/Components/ToggleCellDrawComponent.cs new file mode 100644 index 0000000000..20e2d4fe02 --- /dev/null +++ b/Content.Shared/PowerCell/Components/ToggleCellDrawComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.PowerCell.Components; + +/// +/// Integrate PowerCellDraw and ItemToggle. +/// Make toggling this item require power, and deactivates the item when power runs out. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ToggleCellDrawComponent : Component; diff --git a/Content.Shared/PowerCell/PowerCellDrawComponent.cs b/Content.Shared/PowerCell/PowerCellDrawComponent.cs index e4402e9eff..7af44420a7 100644 --- a/Content.Shared/PowerCell/PowerCellDrawComponent.cs +++ b/Content.Shared/PowerCell/PowerCellDrawComponent.cs @@ -9,7 +9,6 @@ namespace Content.Shared.PowerCell; /// /// /// With ActivatableUI it will activate and deactivate when the ui is opened and closed, drawing power inbetween. -/// Requires to work. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class PowerCellDrawComponent : Component @@ -31,9 +30,8 @@ public sealed partial class PowerCellDrawComponent : Component #endregion /// - /// Whether drawing is enabled, regardless of ItemToggle. + /// Whether drawing is enabled. /// Having no cell will still disable it. - /// Only use this if you really don't want it to use power for some time. /// [DataField, AutoNetworkedField] public bool Enabled = true; diff --git a/Content.Shared/PowerCell/SharedPowerCellSystem.cs b/Content.Shared/PowerCell/SharedPowerCellSystem.cs index 2b2a836633..f098f575c4 100644 --- a/Content.Shared/PowerCell/SharedPowerCellSystem.cs +++ b/Content.Shared/PowerCell/SharedPowerCellSystem.cs @@ -1,6 +1,4 @@ using Content.Shared.Containers.ItemSlots; -using Content.Shared.Item.ItemToggle; -using Content.Shared.Item.ItemToggle.Components; using Content.Shared.PowerCell.Components; using Content.Shared.Rejuvenate; using Robust.Shared.Containers; @@ -13,19 +11,22 @@ public abstract class SharedPowerCellSystem : EntitySystem [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] protected readonly ItemToggleSystem Toggle = default!; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnCellInserted); SubscribeLocalEvent(OnCellRemoved); SubscribeLocalEvent(OnCellInsertAttempt); + } - SubscribeLocalEvent(OnActivateAttempt); - SubscribeLocalEvent(OnToggled); + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + QueueUpdate((ent, ent.Comp)); } private void OnRejuvenate(EntityUid uid, PowerCellSlotComponent component, RejuvenateEvent args) @@ -70,16 +71,13 @@ protected virtual void OnCellRemoved(EntityUid uid, PowerCellSlotComponent compo RaiseLocalEvent(uid, new PowerCellChangedEvent(true), false); } - private void OnActivateAttempt(Entity ent, ref ItemToggleActivateAttemptEvent args) - { - if (!HasDrawCharge(ent, ent.Comp, user: args.User) - || !HasActivatableCharge(ent, ent.Comp, user: args.User)) - args.Cancelled = true; - } - - private void OnToggled(Entity ent, ref ItemToggledEvent args) + /// + /// Makes the draw logic update in the next tick. + /// + public void QueueUpdate(Entity ent) { - ent.Comp.NextUpdateTime = Timing.CurTime; + if (Resolve(ent, ref ent.Comp)) + ent.Comp.NextUpdateTime = Timing.CurTime; } public void SetDrawEnabled(Entity ent, bool enabled) diff --git a/Content.Shared/PowerCell/ToggleCellDrawSystem.cs b/Content.Shared/PowerCell/ToggleCellDrawSystem.cs new file mode 100644 index 0000000000..070937b8b4 --- /dev/null +++ b/Content.Shared/PowerCell/ToggleCellDrawSystem.cs @@ -0,0 +1,49 @@ +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.PowerCell.Components; + +namespace Content.Shared.PowerCell; + +/// +/// Handles events to integrate PowerCellDraw with ItemToggle +/// +public sealed class ToggleCellDrawSystem : EntitySystem +{ + [Dependency] private readonly ItemToggleSystem _toggle = default!; + [Dependency] private readonly SharedPowerCellSystem _cell = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnActivateAttempt); + SubscribeLocalEvent(OnToggled); + SubscribeLocalEvent(OnEmpty); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + _cell.SetDrawEnabled(ent.Owner, _toggle.IsActivated(ent.Owner)); + } + + private void OnActivateAttempt(Entity ent, ref ItemToggleActivateAttemptEvent args) + { + if (!_cell.HasDrawCharge(ent, user: args.User) + || !_cell.HasActivatableCharge(ent, user: args.User)) + args.Cancelled = true; + } + + private void OnToggled(Entity ent, ref ItemToggledEvent args) + { + var uid = ent.Owner; + var draw = Comp(uid); + _cell.QueueUpdate((uid, draw)); + _cell.SetDrawEnabled((uid, draw), args.Activated); + } + + private void OnEmpty(Entity ent, ref PowerCellSlotEmptyEvent args) + { + _toggle.TryDeactivate(ent.Owner); + } +} diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 99779cccd2..d0b65ddfcc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -9870,3 +9870,18 @@ Entries: id: 6690 time: '2025-01-14T08:47:56.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1539 +- author: sleepyyapril + changes: + - type: Tweak + message: Outer clothing will now count as partial identity coverage. + - type: Fix + message: Fixed portal artifacts targeting the Station AI. + - type: Fix + message: Fixed job titles not showing up in various announcements. + - type: Fix + message: Ported some general mob AI fixes. + - type: Fix + message: Fixed energy shield visuals. + id: 6691 + time: '2025-01-14T23:24:39.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1547 diff --git a/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl new file mode 100644 index 0000000000..a5b96eab08 --- /dev/null +++ b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl @@ -0,0 +1,5 @@ +sec-watch-program-name = SecWatch +sec-watch-title = SecWatch 1.0 +sec-watch-no-entries = Everything's calm. Why not enjoy a Monkin Donut? +sec-watch-entry = {$name}, {$job} +sec-watch-no-reason = None given??? diff --git a/Resources/Locale/en-US/random-barks/chicken.ftl b/Resources/Locale/en-US/random-barks/chicken.ftl index fe7070e045..b5044be712 100644 --- a/Resources/Locale/en-US/random-barks/chicken.ftl +++ b/Resources/Locale/en-US/random-barks/chicken.ftl @@ -4,6 +4,6 @@ bark-chicken-3 = Coot Coot Cooot bark-chicken-4 = Food bark-chicken-5 = Where is grass? bark-chicken-6 = Need to eat -bark-chicken-8 = Egg -bark-chicken-9 = Coot coot -bark-chicken-count = 9 +bark-chicken-7 = Egg +bark-chicken-8 = Coot coot +bark-chicken-count = 8 diff --git a/Resources/Maps/Shuttles/emergency_meta.yml b/Resources/Maps/Shuttles/emergency_meta.yml index 544355e090..ffb141c9fc 100644 --- a/Resources/Maps/Shuttles/emergency_meta.yml +++ b/Resources/Maps/Shuttles/emergency_meta.yml @@ -85,7 +85,6 @@ entities: configurators: [] deviceLists: [] transmitFrequencyId: ShuttleTimer - deviceNetId: Wireless - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml index 2c290bd596..ba8bdfe1be 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml @@ -1,6 +1,6 @@ - type: entity name: arctic fox - parent: MobFox + parent: SimpleMobBase id: MobArcticFox description: Wears a regal coat of snowy elegance, belying its cold and resourceful nature. components: @@ -40,6 +40,10 @@ Base: arcticfox_crit Dead: Base: arcticfox_dead + - type: Butcherable + spawned: + - id: FoodMeat + amount: 3 - type: InteractionPopup successChance: 0.5 interactSuccessString: petting-success-soft-floofy @@ -52,6 +56,16 @@ coldDamage: types: Cold: 0.1 + - type: Grammar + attributes: + gender: epicene + - type: Bloodstream + bloodMaxVolume: 100 + - type: MobPrice + price: 400 + - type: Tag + tags: + - VimPilot - type: entity name: security dog diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml index a8ebc8bdbc..9c7e221b86 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml @@ -17,7 +17,6 @@ icon: sprite: DeltaV/Icons/cri.rsi state: cri - - type: CrimeAssistCartridge - type: entity parent: BaseItem @@ -31,14 +30,14 @@ - type: Icon sprite: DeltaV/Objects/Devices/cartridge.rsi state: cart-cri - # - type: UIFragment - # ui: !type:SecWatchUi - # - type: Cartridge - # programName: sec-watch-program-name - # icon: - # sprite: Objects/Weapons/Melee/stunbaton.rsi - # state: stunbaton_on - # - type: SecWatchCartridge + - type: UIFragment + ui: !type:SecWatchUi + - type: Cartridge + programName: sec-watch-program-name + icon: + sprite: Objects/Weapons/Melee/stunbaton.rsi + state: stunbaton_on + - type: SecWatchCartridge - type: entity parent: BaseItem diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml index a7226f9fd8..8cc2695081 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml @@ -16,7 +16,7 @@ map: [ "enum.PdaVisualLayers.IdLight" ] shader: "unshaded" visible: false - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index ac4d430557..0621e7cd69 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -187,6 +187,7 @@ lastVisibility: 0.1 - type: PowerCellDraw drawRate: 1.8 # 200 seconds on the default cell + - type: ToggleCellDraw # throwing star ability - type: ItemCreator action: ActionCreateThrowingStar diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index cda7fe5e41..4ed77b5caa 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -116,6 +116,7 @@ price: 500 - type: PowerCellDraw drawRate: 4 + - type: ToggleCellDraw - type: ItemSlots slots: cell_slot: diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml index 0a8e440e5b..cea803d104 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml @@ -56,6 +56,7 @@ - type: DeviceNetwork deviceNetId: Wireless transmitFrequencyId: SuitSensor + savableAddress: false - type: WirelessNetworkConnection range: 1200 - type: StationLimitedNetwork diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 0d809fd164..3098ea8d58 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -124,6 +124,7 @@ # TODO: or just have sentient speedboots be fast idk - type: PowerCellDraw drawRate: 0.6 + # no ToggleCellDraw since dont want to lose access when power is gone - type: ItemSlots slots: cell_slot: @@ -251,6 +252,7 @@ deviceNetId: Wireless receiveFrequencyId: CyborgControl transmitFrequencyId: RoboticsConsole + savableAddress: false - type: OnUseTimerTrigger delay: 10 examinable: false diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index bc0b7c966b..4d262a9737 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -2371,24 +2371,10 @@ # Code unique spider prototypes or combine them all into one spider and get a # random sprite state when you spawn it. - type: entity - name: tarantula parent: [ SimpleMobBase, MobCombat ] - id: MobGiantSpider - description: Widely recognized to be the literal worst thing in existence. + id: MobSpiderBase + abstract: true components: - - type: Sprite - drawdepth: Mobs - layers: - - map: ["enum.DamageStateVisualLayers.Base", "movement"] - state: tarantula - sprite: Mobs/Animals/spider.rsi - - type: SpriteMovement - movementLayers: - movement: - state: tarantula-moving - noMovementLayers: - movement: - state: tarantula - type: Carriable - type: Physics - type: Fixtures @@ -2402,12 +2388,6 @@ - MobMask layer: - MobLayer - - type: DamageStateVisuals - states: - Alive: - Base: tarantula - Dead: - Base: tarantula_dead - type: Butcherable spawned: - id: FoodMeatSpider @@ -2419,15 +2399,6 @@ thresholds: 0: Alive 90: Dead - - type: MeleeWeapon - altDisarm: false - angle: 0 - animation: WeaponArcBite - soundHit: - path: /Audio/Effects/bite.ogg - damage: - types: - Piercing: 6 - type: SolutionContainerManager solutions: melee: @@ -2509,32 +2480,74 @@ enum.SurgeryUIKey.Key: type: SurgeryBui +- type: entity + parent: MobSpiderBase + id: MobSpiderAngryBase + abstract: true + components: + - type: NpcFactionMember + factions: + - Xeno + - type: InputMover + - type: MobMover + - type: HTN + rootTask: + task: SimpleHostileCompound + - type: GhostRole + makeSentient: true + name: ghost-role-information-giant-spider-name + description: ghost-role-information-giant-spider-description + rules: ghost-role-information-giant-spider-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: entity name: tarantula - parent: MobGiantSpider - id: MobGiantSpiderAngry - suffix: Angry + parent: MobSpiderBase + id: MobGiantSpider + description: Widely recognized to be the literal worst thing in existence. components: - - type: NpcFactionMember - factions: - - Xeno - - type: InputMover - - type: MobMover - - type: HTN - rootTask: - task: SimpleHostileCompound - - type: GhostRole - makeSentient: true - name: ghost-role-information-giant-spider-name - description: ghost-role-information-giant-spider-description - rules: deltav-ghost-role-information-softantag-rules - raffle: - settings: short - - type: GhostTakeoverAvailable + - type: Sprite + drawdepth: Mobs + layers: + - map: ["enum.DamageStateVisualLayers.Base", "movement"] + state: tarantula + sprite: Mobs/Animals/spider.rsi + - type: SpriteMovement + movementLayers: + movement: + state: tarantula-moving + noMovementLayers: + movement: + state: tarantula + - type: DamageStateVisuals + states: + Alive: + Base: tarantula + Critical: + Base: tarantula_dead + Dead: + Base: tarantula_dead + - type: MeleeWeapon + altDisarm: false + angle: 0 + animation: WeaponArcBite + soundHit: + path: /Audio/Effects/bite.ogg + damage: + types: + Piercing: 6 + +- type: entity + parent: + - MobGiantSpider + - MobSpiderAngryBase + id: MobGiantSpiderAngry - type: entity name: clown spider - parent: MobGiantSpiderAngry + parent: MobSpiderAngryBase id: MobClownSpider description: Combines the two most terrifying things in existence, spiders and clowns. components: diff --git a/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml b/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml index 259323fede..c377519ddb 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml @@ -9,3 +9,4 @@ - type: PowerCellDraw drawRate: 0 useRate: 20 + - type: ToggleCellDraw diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index dcb2c30cc5..39b414833a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -57,7 +57,6 @@ - idcard - Belt - type: UnpoweredFlashlight - - type: EtherealLight - type: PointLight enabled: false radius: 1.5 @@ -68,6 +67,7 @@ deviceNetId: Wireless receiveFrequencyId: PDA prefix: device-address-prefix-console + savableAddress: false - type: WirelessNetworkConnection range: 500 - type: CartridgeLoader @@ -202,7 +202,7 @@ accentVColor: "#A32D26" - type: Icon state: pda-interncadet - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -532,7 +532,7 @@ borderColor: "#6f6192" - type: Icon state: pda-lawyer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -926,7 +926,7 @@ accentHColor: "#447987" - type: Icon state: pda-hos - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -979,7 +979,7 @@ accentVColor: "#949137" - type: Icon state: pda-warden - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -1001,7 +1001,7 @@ borderColor: "#A32D26" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -1342,7 +1342,7 @@ borderColor: "#774705" - type: Icon state: pda-detective - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -1373,7 +1373,7 @@ accentVColor: "#d7d7d0" - type: Icon state: pda-brigmedic - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge @@ -1472,7 +1472,7 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-seniorofficer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 932132705e..fcd3b7821d 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -1624,6 +1624,7 @@ right: - state: inhand-right-blade shader: unshaded + - type: ItemTogglePointLight - type: DisarmMalus malus: 0 - type: StaminaDamageOnHit diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index ac23bd3995..e7f5ec7d2b 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -359,6 +359,7 @@ radius: 1.5 energy: 2 color: blue + - type: ItemTogglePointLight - type: Reflect reflectProb: 0.95 innate: true diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml index 0a7041ea54..6697099631 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml @@ -54,6 +54,7 @@ staminaCost: 22.5 soundHit: path: /Audio/Weapons/smash.ogg + - type: ToggleCellDraw - type: entity id: Defibrillator diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml index df9c27149d..7d865b53c8 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml @@ -51,6 +51,7 @@ components: - type: PowerCellDraw drawRate: 1.2 #Calculated for 5 minutes on a small cell + - type: ToggleCellDraw - type: ActivatableUIRequiresPowerCell - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index a90f7099ad..f32b17a8d9 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -72,6 +72,7 @@ - type: PowerCellDraw drawRate: 1 useRate: 0 + - type: ToggleCellDraw - type: entity id: AnomalyLocatorEmpty @@ -105,6 +106,7 @@ - type: PowerCellDraw drawRate: 1 useRate: 0 + - type: ToggleCellDraw - type: entity id: AnomalyLocatorWideEmpty diff --git a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml index 6491f699f0..52fef416b2 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml @@ -25,8 +25,8 @@ True: { visible: true } False: { visible: false } - type: PowerCellDraw - drawRate: 3 - useRate: 100 + drawRate: 1.5 + - type: ToggleCellDraw - type: ActivatableUI key: enum.RadarConsoleUiKey.Key inHandsOnly: true diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index 1aa79d8ace..a84ad6d104 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -107,6 +107,7 @@ collection: lighterOnSounds endSound: collection: lighterOffSounds + - type: ItemTogglePointLight - type: entity name: cheap lighter @@ -237,6 +238,7 @@ netsync: false radius: 1.2 #slightly stronger than the other lighters color: orange + - type: ItemTogglePointLight - type: UseDelay - type: IgnitionSource ignited: false diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 8c0e1e1716..6a8895e37c 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -105,6 +105,7 @@ radius: 1.5 color: orange netsync: false + - type: ItemTogglePointLight - type: Appearance - type: RequiresEyeProtection - type: PhysicalComposition diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 0fe7455369..4683bf04e0 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -184,6 +184,7 @@ - type: ItemToggle onUse: false - type: PowerCellDraw + - type: ToggleCellDraw - type: Sprite sprite: Objects/Weapons/Guns/Launchers/tether_gun.rsi layers: @@ -231,6 +232,7 @@ - type: ItemToggle onUse: false - type: PowerCellDraw + - type: ToggleCellDraw - type: Sprite sprite: Objects/Weapons/Guns/Launchers/force_gun.rsi layers: diff --git a/Resources/Prototypes/NPCs/Combat/melee.yml b/Resources/Prototypes/NPCs/Combat/melee.yml index b0746e5679..9cbfbe7ca0 100644 --- a/Resources/Prototypes/NPCs/Combat/melee.yml +++ b/Resources/Prototypes/NPCs/Combat/melee.yml @@ -3,48 +3,55 @@ - type: htnCompound id: MeleeCombatCompound branches: - # Pickup weapon if we don't have one. + - tasks: + - !type:HTNPrimitiveTask + operator: !type:UtilityOperator + proto: NearbyMeleeTargets + - !type:HTNCompoundTask + task: BeforeMeleeAttackTargetCompound + +- type: htnCompound + id: BeforeMeleeAttackTargetCompound + branches: - preconditions: - - !type:ActiveHandComponentPrecondition - components: - # Just serializer things - - type: MeleeWeapon - damage: - types: - Blunt: 0 - invert: true + - !type:BuckledPrecondition + isBuckled: true tasks: - - !type:HTNCompoundTask - task: PickupMeleeCompound + - !type:HTNPrimitiveTask + operator: !type:UnbuckleOperator + shutdownState: TaskFinished - preconditions: - - !type:BuckledPrecondition - isBuckled: true + - !type:PulledPrecondition + isPulled: true tasks: - - !type:HTNPrimitiveTask - operator: !type:UnbuckleOperator - shutdownState: TaskFinished + - !type:HTNPrimitiveTask + operator: !type:UnPullOperator + shutdownState: TaskFinished - preconditions: - - !type:InContainerPrecondition - isInContainer: true + - !type:InContainerPrecondition + isInContainer: true tasks: - - !type:HTNCompoundTask - task: EscapeCompound + - !type:HTNCompoundTask + task: EscapeCompound + # Pickup weapon if we don't have one. - preconditions: - - !type:PulledPrecondition - isPulled: true + - !type:ActiveHandComponentPrecondition + components: + # Just serializer things + - type: MeleeWeapon + damage: + types: + Blunt: 0 + invert: true tasks: - - !type:HTNPrimitiveTask - operator: !type:UnPullOperator - shutdownState: TaskFinished + - !type:HTNCompoundTask + task: PickupMeleeCompound # Melee combat (unarmed or otherwise) - tasks: - - !type:HTNPrimitiveTask - operator: !type:UtilityOperator - proto: NearbyMeleeTargets - !type:HTNCompoundTask task: MeleeAttackTargetCompound