diff --git a/Content.Client/ClientPreferencesManager.cs b/Content.Client/ClientPreferencesManager.cs index c7abc9b5f9..298ba8e80d 100644 --- a/Content.Client/ClientPreferencesManager.cs +++ b/Content.Client/ClientPreferencesManager.cs @@ -26,6 +26,7 @@ namespace Content.Client { _netManager.RegisterNetMessage(nameof(MsgPreferencesAndSettings), HandlePreferencesAndSettings); + _netManager.RegisterNetMessage(nameof(MsgUpdateCharacter)); } public void SelectCharacter(ICharacterProfile profile) diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 9e8172d4cf..28c04b08a2 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -125,7 +125,10 @@ namespace Content.Client /// public static void DetachPlayerFromEntity(EntityDetachedEventArgs eventArgs) { - eventArgs.OldEntity.RemoveComponent(); + if (!eventArgs.OldEntity.Deleted) + { + eventArgs.OldEntity.RemoveComponent(); + } } public override void PostInit() diff --git a/Content.Client/EscapeMenuOwner.cs b/Content.Client/EscapeMenuOwner.cs index 5cbd33c1d8..93acf5b298 100644 --- a/Content.Client/EscapeMenuOwner.cs +++ b/Content.Client/EscapeMenuOwner.cs @@ -6,6 +6,7 @@ using Robust.Client.Interfaces.Placement; using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.Interfaces.State; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; diff --git a/Content.Client/GameObjects/Components/Items/ItemComponent.cs b/Content.Client/GameObjects/Components/Items/ItemComponent.cs index 4c6a1d0402..b3efb0fa16 100644 --- a/Content.Client/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ItemComponent.cs @@ -1,4 +1,6 @@ -using Content.Shared.GameObjects; +using Content.Client.GameObjects.Components.Storage; +using Content.Client.Interfaces.GameObjects.Components.Interaction; +using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; using Robust.Client.Graphics; using Robust.Client.Interfaces.ResourceManagement; diff --git a/Content.Client/GameObjects/Components/Mobs/BuckleComponent.cs b/Content.Client/GameObjects/Components/Mobs/BuckleComponent.cs index 2442fd0d6d..f793567e57 100644 --- a/Content.Client/GameObjects/Components/Mobs/BuckleComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/BuckleComponent.cs @@ -1,16 +1,19 @@ -using Content.Shared.GameObjects.Components.Mobs; +using Content.Client.GameObjects.Components.Strap; +using Content.Client.Interfaces.GameObjects.Components.Interaction; +using Content.Shared.GameObjects.Components.Mobs; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.Maths; namespace Content.Client.GameObjects.Components.Mobs { [RegisterComponent] - public class BuckleComponent : SharedBuckleComponent + public class BuckleComponent : SharedBuckleComponent, IClientDraggable { private bool _buckled; private int? _originalDrawDepth; + protected override bool Buckled => _buckled; + public override void HandleComponentState(ComponentState curState, ComponentState nextState) { if (!(curState is BuckleComponentState buckle)) @@ -39,6 +42,14 @@ namespace Content.Client.GameObjects.Components.Mobs } } - protected override bool Buckled => _buckled; + bool IClientDraggable.ClientCanDropOn(CanDropEventArgs eventArgs) + { + return eventArgs.Target.HasComponent(); + } + + bool IClientDraggable.ClientCanDrag(CanDragEventArgs eventArgs) + { + return true; + } } } diff --git a/Content.Client/GameObjects/Components/Mobs/BuckleVisualizer2D.cs b/Content.Client/GameObjects/Components/Mobs/BuckleVisualizer2D.cs index 3dfe3d10a4..755439c753 100644 --- a/Content.Client/GameObjects/Components/Mobs/BuckleVisualizer2D.cs +++ b/Content.Client/GameObjects/Components/Mobs/BuckleVisualizer2D.cs @@ -17,7 +17,7 @@ namespace Content.Client.GameObjects.Components.Mobs return; } - if (!component.TryGetData(SharedStrapComponent.StrapVisuals.RotationAngle, out var angle)) + if (!component.TryGetData(StrapVisuals.RotationAngle, out var angle)) { return; } diff --git a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs b/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs index 5b5c24d579..e1a1cb8b38 100644 --- a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs @@ -1,18 +1,21 @@ -using System.Collections.Generic; -using Content.Client.Graphics.Overlays; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.Interfaces; using Robust.Client.GameObjects; using Robust.Client.Graphics.Overlays; using Robust.Client.Interfaces.Graphics.Overlays; -using Robust.Client.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; +using Robust.Shared.Interfaces.Reflection; using Robust.Shared.IoC; using Robust.Shared.Log; -using Robust.Shared.Players; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; -namespace Content.Client.GameObjects +namespace Content.Client.GameObjects.Components.Mobs { /// /// A character UI component which shows the current damage state of the mob (living/dead) @@ -21,48 +24,33 @@ namespace Content.Client.GameObjects [ComponentReference(typeof(SharedOverlayEffectsComponent))] public sealed class ClientOverlayEffectsComponent : SharedOverlayEffectsComponent//, ICharacterUI { - /// /// An enum representing the current state being applied to the user /// - private ScreenEffects _currentEffect = ScreenEffects.None; + private readonly List _currentEffects = new List(); + + [ViewVariables(VVAccess.ReadOnly)] + public List ActiveOverlays + { + get => _currentEffects; + set => SetEffects(value); + } #pragma warning disable 649 // Required dependencies [Dependency] private readonly IOverlayManager _overlayManager; - [Dependency] private readonly IPlayerManager _playerManager; + [Dependency] private readonly IReflectionManager _reflectionManager; #pragma warning restore 649 - /// - /// Holds the screen effects that can be applied mapped ot their relevant overlay - /// - private Dictionary _effectsDictionary; - - /// - /// Allows calculating if we need to act due to this component being controlled by the current mob - /// - private bool CurrentlyControlled => _playerManager.LocalPlayer.ControlledEntity == Owner; - - public override void OnAdd() - { - base.OnAdd(); - - _effectsDictionary = new Dictionary() - { - { ScreenEffects.CircleMask, new CircleMaskOverlay() }, - { ScreenEffects.GradientCircleMask, new GradientCircleMask() } - }; - } - public override void HandleMessage(ComponentMessage message, IComponent component) { switch (message) { case PlayerAttachedMsg _: - SetOverlay(_currentEffect); + SetEffects(ActiveOverlays); break; case PlayerDetachedMsg _: - RemoveOverlay(); + ActiveOverlays = new List(); break; } } @@ -70,42 +58,77 @@ namespace Content.Client.GameObjects public override void HandleComponentState(ComponentState curState, ComponentState nextState) { base.HandleComponentState(curState, nextState); - if (!(curState is OverlayEffectComponentState state) || _currentEffect == state.ScreenEffect) return; - SetOverlay(state.ScreenEffect); - } - - private void SetOverlay(ScreenEffects effect) - { - RemoveOverlay(); - - _currentEffect = effect; - - ApplyOverlay(); - } - - private void RemoveOverlay() - { - if (CurrentlyControlled && _currentEffect != ScreenEffects.None) + if (!(curState is OverlayEffectComponentState state) || ActiveOverlays.Equals(state.Overlays)) { - var appliedEffect = _effectsDictionary[_currentEffect]; - _overlayManager.RemoveOverlay(appliedEffect.ID); + return; } - _currentEffect = ScreenEffects.None; + ActiveOverlays = state.Overlays; } - private void ApplyOverlay() + private void SetEffects(List newOverlays) { - if (CurrentlyControlled && _currentEffect != ScreenEffects.None) + foreach (var container in ActiveOverlays.ShallowClone()) { - var overlay = _effectsDictionary[_currentEffect]; - if (_overlayManager.HasOverlay(overlay.ID)) + if (!newOverlays.Contains(container)) { - return; + RemoveOverlay(container); } - _overlayManager.AddOverlay(overlay); - Logger.InfoS("overlay", $"Changed overlay to {overlay}"); } + + foreach (var container in newOverlays) + { + if (!ActiveOverlays.Contains(container)) + { + AddOverlay(container); + } + } + } + + private void RemoveOverlay(OverlayContainer container) + { + ActiveOverlays.Remove(container); + _overlayManager.RemoveOverlay(container.ID); + } + + private void AddOverlay(OverlayContainer container) + { + ActiveOverlays.Add(container); + if (TryCreateOverlay(container, out var overlay)) + { + _overlayManager.AddOverlay(overlay); + } + else + { + Logger.ErrorS("overlay", $"Could not add overlay {container.ID}"); + } + } + + private bool TryCreateOverlay(OverlayContainer container, out Overlay overlay) + { + var overlayTypes = _reflectionManager.GetAllChildren(); + var foundType = overlayTypes.FirstOrDefault(t => t.Name == container.ID); + + if (foundType != null) + { + overlay = Activator.CreateInstance(foundType) as Overlay; + var configurable = foundType + .GetInterfaces() + .FirstOrDefault(type => + type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IConfigurable<>) + && type.GenericTypeArguments.First() == container.GetType()); + + if (configurable != null) + { + var method = overlay?.GetType().GetMethod("Configure"); + method?.Invoke(overlay, new []{ container }); + } + + return true; + } + + overlay = default; + return false; } } } diff --git a/Content.Client/GameObjects/Components/PlaceableSurfaceComponent.cs b/Content.Client/GameObjects/Components/PlaceableSurfaceComponent.cs new file mode 100644 index 0000000000..88c12cad83 --- /dev/null +++ b/Content.Client/GameObjects/Components/PlaceableSurfaceComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.GameObjects.Components; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components +{ + [RegisterComponent] + public class PlaceableSurfaceComponent : SharedPlaceableSurfaceComponent + { + + } +} diff --git a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs index 0a0b948237..4fc955ede6 100644 --- a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs +++ b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Content.Shared.GameObjects.Components.Storage; using Content.Client.Interfaces.GameObjects; +using Content.Client.Interfaces.GameObjects.Components.Interaction; using Robust.Client.Graphics.Drawing; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.UserInterface; @@ -21,7 +22,7 @@ namespace Content.Client.GameObjects.Components.Storage /// Client version of item storage containers, contains a UI which displays stored entities and their size /// [RegisterComponent] - public class ClientStorageComponent : SharedStorageComponent + public class ClientStorageComponent : SharedStorageComponent, IClientDraggable { private Dictionary StoredEntities { get; set; } = new Dictionary(); private int StorageSizeUsed; @@ -316,5 +317,17 @@ namespace Content.Client.GameObjects.Components.Storage AddChild(hBoxContainer); } } + + public bool ClientCanDropOn(CanDropEventArgs eventArgs) + { + //can only drop on placeable surfaces to empty out contents + return eventArgs.Target.HasComponent(); + } + + public bool ClientCanDrag(CanDragEventArgs eventArgs) + { + //always draggable, at least for now + return true; + } } } diff --git a/Content.Client/GameObjects/Components/Strap/StrapComponent.cs b/Content.Client/GameObjects/Components/Strap/StrapComponent.cs new file mode 100644 index 0000000000..eabb96b01c --- /dev/null +++ b/Content.Client/GameObjects/Components/Strap/StrapComponent.cs @@ -0,0 +1,22 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Strap; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.Strap +{ + [RegisterComponent] + public class StrapComponent : SharedStrapComponent + { + public override StrapPosition Position { get; protected set; } + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (!(curState is StrapComponentState strap)) + { + return; + } + + Position = strap.Position; + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs b/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs new file mode 100644 index 0000000000..feb97342a2 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs @@ -0,0 +1,397 @@ +using System.Collections.Generic; +using Content.Client.Interfaces.GameObjects.Components.Interaction; +using Content.Client.State; +using Content.Shared.GameObjects; +using Content.Shared.GameObjects.EntitySystemMessages; +using Content.Shared.GameObjects.EntitySystems; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.GameObjects.EntitySystems; +using Robust.Client.Graphics.Shaders; +using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Client.Interfaces.Input; +using Robust.Client.Interfaces.State; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Input; +using Robust.Shared.Input.Binding; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; + +namespace Content.Client.GameObjects.EntitySystems +{ + /// + /// Handles clientside drag and drop logic + /// + [UsedImplicitly] + public class DragDropSystem : EntitySystem + { + // drag will be triggered when mouse leaves this deadzone around the click position. + private const float DragDeadzone = 2f; + // how often to recheck possible targets (prevents calling expensive + // check logic each update) + private const float TargetRecheckInterval = 0.25f; + + // if a drag ends up being cancelled and it has been under this + // amount of time since the mousedown, we will "replay" the original + // mousedown event so it can be treated like a regular click + private const float MaxMouseDownTimeForReplayingClick = 0.85f; + + private const string ShaderDropTargetInRange = "SelectionOutlineInrange"; + private const string ShaderDropTargetOutOfRange = "SelectionOutline"; + +#pragma warning disable 649 + [Dependency] private readonly IStateManager _stateManager; + [Dependency] private readonly IEntityManager _entityManager; + [Dependency] private readonly IInputManager _inputManager; + [Dependency] private readonly IEyeManager _eyeManager; + [Dependency] private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IMapManager _mapManager; +#pragma warning restore 649 + + // entity performing the drag action + private IEntity _dragger; + private IEntity _draggedEntity; + private IClientDraggable _draggable; + private IEntity _dragShadow; + private DragState _state; + // time since mouse down over the dragged entity + private float _mouseDownTime; + // screen pos where the mouse down began + private Vector2 _mouseDownScreenPos; + // how much time since last recheck of all possible targets + private float _targetRecheckTime; + // reserved initial mousedown event so we can replay it if no drag ends up being performed + private PointerInputCmdHandler.PointerInputCmdArgs? _savedMouseDown; + // whether we are currently replaying the original mouse down, so we + // can ignore any events sent to this system + private bool _isReplaying; + + private ShaderInstance _dropTargetInRangeShader; + private ShaderInstance _dropTargetOutOfRangeShader; + private SharedInteractionSystem _interactionSystem; + private InputSystem _inputSystem; + + private List highlightedSprites = new List(); + + private enum DragState + { + NotDragging, + // not dragging yet, waiting to see + // if they hold for long enough + MouseDown, + // currently dragging something + Dragging, + } + + + public override void Initialize() + { + _state = DragState.NotDragging; + + _dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance(); + _dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance(); + _interactionSystem = EntitySystem.Get(); + _inputSystem = EntitySystem.Get(); + // needs to fire on mouseup and mousedown so we can detect a drag / drop + CommandBinds.Builder + .Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false)) + .Register(); + + } + + public override void Shutdown() + { + CancelDrag(false, null); + CommandBinds.Unregister(); + base.Shutdown(); + } + + private bool OnUse(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + // not currently predicted + if (_inputSystem.Predicted) return false; + + // currently replaying a saved click, don't handle this because + // we already decided this click doesn't represent an actual drag attempt + if (_isReplaying) return false; + + if (args.State == BoundKeyState.Down) + { + return OnUseMouseDown(args); + } + else if (args.State == BoundKeyState.Up) + { + return OnUseMouseUp(args); + } + + return false; + } + + private bool OnUseMouseDown(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + var dragger = args.Session.AttachedEntity; + // cancel any current dragging if there is one (shouldn't be because they would've had to have lifted + // the mouse, canceling the drag, but just being cautious) + CancelDrag(false, null); + + // possibly initiating a drag + // check if the clicked entity is draggable + if (_entityManager.TryGetEntity(args.EntityUid, out var entity)) + { + // check if the entity is reachable + if (_interactionSystem.InRangeUnobstructed(dragger.Transform.MapPosition, + entity.Transform.MapPosition, ignoredEnt: dragger) == false) + { + { + return false; + } + } + foreach (var draggable in entity.GetAllComponents()) + { + var dragEventArgs = new CanDragEventArgs(args.Session.AttachedEntity, entity); + if (draggable.ClientCanDrag(dragEventArgs)) + { + // wait to initiate a drag + _dragger = dragger; + _draggedEntity = entity; + _draggable = draggable; + _mouseDownTime = 0; + _state = DragState.MouseDown; + _mouseDownScreenPos = _inputManager.MouseScreenPosition; + // don't want anything else to process the click, + // but we will save the event so we can "re-play" it if this drag does + // not turn into an actual drag so the click can be handled normally + _savedMouseDown = args; + return true; + } + } + } + + return false; + } + + private bool OnUseMouseUp(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + if (_state == DragState.MouseDown) + { + // quick mouseup, definitely treat it as a normal click by + // replaying the original + CancelDrag(true, args.OriginalMessage); + return false; + } + if (_state != DragState.Dragging) return false; + + // remaining CancelDrag calls will not replay the click because + // by this time we've determined the input was actually a drag attempt + + + // tell the server we are dropping if we are over a valid drop target in range. + // We don't use args.EntityUid here because drag interactions generally should + // work even if there's something "on top" of the drop target + if (_interactionSystem.InRangeUnobstructed(_dragger.Transform.MapPosition, + args.Coordinates.ToMap(_mapManager), ignoredEnt: _dragger) == false) + { + { + CancelDrag(false, null); + return false; + } + } + + var entities = GameScreenBase.GetEntitiesUnderPosition(_stateManager, args.Coordinates); + foreach (var entity in entities) + { + // check if it's able to be dropped on by current dragged entity + if (_draggable.ClientCanDropOn(new CanDropEventArgs(_dragger, _draggedEntity, entity))) + { + // tell the server about the drop attempt + RaiseNetworkEvent(new DragDropMessage(args.Coordinates, _draggedEntity.Uid, + entity.Uid)); + + CancelDrag(false, null); + return true; + } + } + CancelDrag(false, null); + return false; + } + + private void StartDragging() + { + // this is checked elsewhere but adding this as a failsafe + if (_draggedEntity == null || _draggedEntity.Deleted) + { + Logger.Error("Programming error. Cannot initiate drag, no dragged entity or entity" + + " was deleted."); + return; + } + + if (_draggedEntity.TryGetComponent(out var draggedSprite)) + { + _state = DragState.Dragging; + // pop up drag shadow under mouse + var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition); + _dragShadow = _entityManager.SpawnEntity("dragshadow", mousePos); + var dragSprite = _dragShadow.GetComponent(); + dragSprite.CopyFrom(draggedSprite); + dragSprite.RenderOrder = EntityManager.CurrentTick.Value; + dragSprite.Color = dragSprite.Color.WithAlpha(0.7f); + // keep it on top of everything + dragSprite.DrawDepth = (int) DrawDepth.Overlays; + + HighlightTargets(); + } + else + { + Logger.Warning("Unable to display drag shadow for {0} because it" + + " has no sprite component.", _draggedEntity.Name); + } + } + + private void HighlightTargets() + { + if (_state != DragState.Dragging || _draggedEntity == null || + _draggedEntity.Deleted || _dragShadow == null || _dragShadow.Deleted) + { + Logger.Warning("Programming error. Can't highlight drag and drop targets, not currently " + + "dragging anything or dragged entity / shadow was deleted."); + return; + } + + // highlights the possible targets which are visible + // and able to be dropped on by the current dragged entity + + // remove current highlights + RemoveHighlights(); + + // find possible targets on screen even if not reachable + // TODO: Duplicated in SpriteSystem + var pvsBounds = _eyeManager.GetWorldViewport().Enlarged(5); + var pvsEntities = EntityManager.GetEntitiesIntersecting(_eyeManager.CurrentMap, pvsBounds, true); + foreach (var pvsEntity in pvsEntities) + { + if (pvsEntity.TryGetComponent(out var inRangeSprite)) + { + // can't highlight if there's no sprite or it's not visible + if (inRangeSprite.Visible == false) continue; + + // check if it's able to be dropped on by current dragged entity + if (_draggable.ClientCanDropOn(new CanDropEventArgs(_dragger, _draggedEntity, pvsEntity))) + { + // highlight depending on whether its in or out of range + var inRange = _interactionSystem.InRangeUnobstructed(_dragger.Transform.MapPosition, + pvsEntity.Transform.MapPosition, ignoredEnt: _dragger); + inRangeSprite.PostShader = inRange ? _dropTargetInRangeShader : _dropTargetOutOfRangeShader; + inRangeSprite.RenderOrder = EntityManager.CurrentTick.Value; + highlightedSprites.Add(inRangeSprite); + } + } + } + } + + private void RemoveHighlights() + { + foreach (var highlightedSprite in highlightedSprites) + { + highlightedSprite.PostShader = null; + highlightedSprite.RenderOrder = 0; + } + highlightedSprites.Clear(); + } + + /// + /// Cancels the drag, firing our saved drag event if instructed to do so and + /// we are within the threshold for replaying the click + /// (essentially reverting the drag attempt and allowing the original click + /// to proceed as if no drag was performed) + /// + /// if fireSavedCmd is true, this should be passed with the value of + /// the pointer cmd that caused the drag to be cancelled + private void CancelDrag(bool fireSavedCmd, FullInputCmdMessage cause) + { + RemoveHighlights(); + if (_dragShadow != null) + { + _entityManager.DeleteEntity(_dragShadow); + } + + _dragShadow = null; + _draggedEntity = null; + _draggable = null; + _dragger = null; + _state = DragState.NotDragging; + + _mouseDownTime = 0; + + if (fireSavedCmd && _savedMouseDown.HasValue && _mouseDownTime < MaxMouseDownTimeForReplayingClick) + { + var savedValue = _savedMouseDown.Value; + _isReplaying = true; + // adjust the timing info based on the current tick so it appears as if it happened now + var replayMsg = savedValue.OriginalMessage; + var adjustedInputMsg = new FullInputCmdMessage(cause.Tick, cause.SubTick, replayMsg.InputFunctionId, replayMsg.State, replayMsg.Coordinates, replayMsg.ScreenCoordinates, replayMsg.Uid); + + _inputSystem.HandleInputCommand(savedValue.Session, EngineKeyFunctions.Use, + adjustedInputMsg, true); + _isReplaying = false; + } + + _savedMouseDown = null; + + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + if (_state == DragState.MouseDown) + { + var screenPos = _inputManager.MouseScreenPosition; + if (_draggedEntity == null || _draggedEntity.Deleted) + { + // something happened to the clicked entity or we moved the mouse off the target so + // we shouldn't replay the original click + CancelDrag(false, null); + return; + } + else if ((_mouseDownScreenPos - screenPos).Length > DragDeadzone) + { + // initiate actual drag + StartDragging(); + _mouseDownTime = 0; + } + } + else if (_state == DragState.Dragging) + { + if (_draggedEntity == null || _draggedEntity.Deleted) + { + CancelDrag(false, null); + return; + } + // still in range of the thing we are dragging? + if (_interactionSystem.InRangeUnobstructed(_dragger.Transform.MapPosition, + _draggedEntity.Transform.MapPosition, ignoredEnt: _dragger) == false) + { + CancelDrag(false, null); + return; + } + + // keep dragged entity under mouse + var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition); + // TODO: would use MapPosition instead if it had a setter, but it has no setter. + // is that intentional, or should we add a setter for Transform.MapPosition? + _dragShadow.Transform.WorldPosition = mousePos.Position; + + _targetRecheckTime += frameTime; + if (_targetRecheckTime > TargetRecheckInterval) + { + HighlightTargets(); + _targetRecheckTime = 0; + } + + } + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/MoverSystem.cs b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs index 0197ed1b97..37689e355c 100644 --- a/Content.Client/GameObjects/EntitySystems/MoverSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs @@ -46,7 +46,7 @@ namespace Content.Client.GameObjects.EntitySystems protected override void SetController(PhysicsComponent physics) { - ((PhysicsComponent)physics).SetController(); + physics.SetController(); } } } diff --git a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs index 3b0a1358ce..ef6832480a 100644 --- a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs +++ b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs @@ -1,4 +1,5 @@ -using Robust.Client.Graphics.Drawing; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; using Robust.Client.Graphics.Shaders; using Robust.Client.Interfaces.Graphics.ClientEye; @@ -17,7 +18,7 @@ namespace Content.Client.Graphics.Overlays public override OverlaySpace Space => OverlaySpace.WorldSpace; - public CircleMaskOverlay() : base(nameof(CircleMaskOverlay)) + public CircleMaskOverlay() : base(nameof(OverlayType.CircleMaskOverlay)) { IoCManager.InjectDependencies(this); Shader = _prototypeManager.Index("CircleMask").Instance(); diff --git a/Content.Client/Graphics/Overlays/FlashOverlay.cs b/Content.Client/Graphics/Overlays/FlashOverlay.cs new file mode 100644 index 0000000000..f156225434 --- /dev/null +++ b/Content.Client/Graphics/Overlays/FlashOverlay.cs @@ -0,0 +1,73 @@ +using System.Net.Mime; +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.Interfaces; +using Robust.Client.Graphics; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Graphics.Overlays; +using Robust.Client.Graphics.Shaders; +using Robust.Client.Interfaces.Graphics; +using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Shared.Interfaces.Timing; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using Color = Robust.Shared.Maths.Color; + +namespace Content.Client.Graphics.Overlays +{ + public class FlashOverlay : Overlay, IConfigurable + { +#pragma warning disable 649 + [Dependency] private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IClyde _displayManager; + [Dependency] private readonly IGameTiming _gameTiming; +#pragma warning restore 649 + + public override OverlaySpace Space => OverlaySpace.ScreenSpace; + private double _startTime; + private int lastsFor = 5000; + private Texture _screenshotTexture; + + public FlashOverlay() : base(nameof(OverlayType.FlashOverlay)) + { + IoCManager.InjectDependencies(this); + Shader = _prototypeManager.Index("FlashedEffect").Instance().Duplicate(); + + _startTime = _gameTiming.CurTime.TotalMilliseconds; + _displayManager.Screenshot(ScreenshotType.BeforeUI, image => + { + var rgba32Image = image.CloneAs(Configuration.Default); + _screenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); + }); + } + + protected override void Draw(DrawingHandleBase handle) + { + var percentComplete = (float) ((_gameTiming.CurTime.TotalMilliseconds - _startTime) / lastsFor); + Shader?.SetParameter("percentComplete", percentComplete); + + var screenSpaceHandle = handle as DrawingHandleScreen; + var screenSize = UIBox2.FromDimensions((0, 0), _displayManager.ScreenSize); + + if (_screenshotTexture != null) + { + screenSpaceHandle?.DrawTextureRect(_screenshotTexture, screenSize); + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _screenshotTexture = null; + } + + public void Configure(TimedOverlayContainer parameters) + { + lastsFor = parameters.Length; + } + } +} diff --git a/Content.Client/Graphics/Overlays/GradientCircleMask.cs b/Content.Client/Graphics/Overlays/GradientCircleMask.cs index 72b1a7e3c3..e95fe30d83 100644 --- a/Content.Client/Graphics/Overlays/GradientCircleMask.cs +++ b/Content.Client/Graphics/Overlays/GradientCircleMask.cs @@ -1,4 +1,5 @@ -using Robust.Client.Graphics.Drawing; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; using Robust.Client.Graphics.Shaders; using Robust.Client.Interfaces.Graphics.ClientEye; @@ -8,7 +9,7 @@ using Robust.Shared.Prototypes; namespace Content.Client.Graphics.Overlays { - public class GradientCircleMask : Overlay + public class GradientCircleMaskOverlay : Overlay { #pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager; @@ -16,7 +17,7 @@ namespace Content.Client.Graphics.Overlays #pragma warning restore 649 public override OverlaySpace Space => OverlaySpace.WorldSpace; - public GradientCircleMask() : base(nameof(GradientCircleMask)) + public GradientCircleMaskOverlay() : base(nameof(OverlayType.GradientCircleMaskOverlay)) { IoCManager.InjectDependencies(this); Shader = _prototypeManager.Index("GradientCircleMask").Instance(); diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index 838d82a380..ce60d6b7f5 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -25,7 +25,6 @@ "ItemTeleporter", "Portal", "EntityStorage", - "PlaceableSurface", "Wirecutter", "Screwdriver", "Multitool", @@ -116,7 +115,6 @@ "Utensil", "UnarmedCombat", "TimedSpawner", - "Strap", "NodeContainer", "PowerSupplier", "PowerConsumer", diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index f9636dc01f..5e54b537dc 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -13,6 +13,7 @@ namespace Content.Client.Input { var common = contexts.GetContext("common"); common.AddFunction(ContentKeyFunctions.FocusChat); + common.AddFunction(ContentKeyFunctions.FocusOOC); common.AddFunction(ContentKeyFunctions.ExamineEntity); common.AddFunction(ContentKeyFunctions.OpenTutorial); common.AddFunction(ContentKeyFunctions.TakeScreenshot); diff --git a/Content.Client/Interfaces/GameObjects/Components/Interaction/IClientDraggable.cs b/Content.Client/Interfaces/GameObjects/Components/Interaction/IClientDraggable.cs new file mode 100644 index 0000000000..26c36d878c --- /dev/null +++ b/Content.Client/Interfaces/GameObjects/Components/Interaction/IClientDraggable.cs @@ -0,0 +1,59 @@ +using System; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Client.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface allows a local client to initiate dragging of the component's entity by mouse, for drag and + /// drop interactions. The actual logic of what happens on drop + /// is handled by IDragDrop + /// + public interface IClientDraggable + { + + /// + /// Invoked on entities visible to the user to check if this component's entity + /// can be dropped on the indicated target entity. No need to check range / reachability in here. + /// + /// true iff target is a valid target to be dropped on by this + /// component's entity. Returning true will cause the target entity to be highlighted as a potential + /// target and allow dropping when in range. + bool ClientCanDropOn(CanDropEventArgs eventArgs); + + /// + /// Invoked clientside when user is attempting to initiate a drag with this component's entity + /// in range. Return true if the drag should be initiated. It's fine to + /// return true even if there wouldn't be any valid targets - just return true + /// if this entity is in a "draggable" state. + /// + /// + /// true iff drag should be initiated + bool ClientCanDrag(CanDragEventArgs eventArgs); + } + + public class CanDropEventArgs : EventArgs + { + public CanDropEventArgs(IEntity user, IEntity dragged, IEntity target) + { + User = user; + Dragged = dragged; + Target = target; + } + + public IEntity User { get; } + public IEntity Dragged { get; } + public IEntity Target { get; } + } + + public class CanDragEventArgs : EventArgs + { + public CanDragEventArgs(IEntity user, IEntity dragged) + { + User = user; + Dragged = dragged; + } + + public IEntity User { get; } + public IEntity Dragged { get; } + } +} diff --git a/Content.Client/Sandbox/SandboxManager.cs b/Content.Client/Sandbox/SandboxManager.cs index 65559ba958..9a83f2b29e 100644 --- a/Content.Client/Sandbox/SandboxManager.cs +++ b/Content.Client/Sandbox/SandboxManager.cs @@ -8,6 +8,7 @@ using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; @@ -36,7 +37,7 @@ namespace Content.Client.Sandbox private SandboxWindow _window; private EntitySpawnWindow _spawnWindow; private TileSpawnWindow _tilesSpawnWindow; - private bool _sandboxWindowToggled = false; + private bool _sandboxWindowToggled; public void Initialize() { @@ -114,6 +115,7 @@ namespace Content.Client.Sandbox { _window = null; _gameHud.SandboxButtonDown = false; + _sandboxWindowToggled = false; } private void OnRespawnButtonOnOnPressed(BaseButton.ButtonEventArgs args) diff --git a/Content.Client/ScreenshotHook.cs b/Content.Client/ScreenshotHook.cs index 529a469b72..f3a7565bed 100644 --- a/Content.Client/ScreenshotHook.cs +++ b/Content.Client/ScreenshotHook.cs @@ -5,6 +5,7 @@ using Content.Shared.Input; using Robust.Client.Interfaces.Graphics; using Robust.Client.Interfaces.Input; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.Resources; using Robust.Shared.IoC; using Robust.Shared.Log; diff --git a/Content.Client/State/GameScreen.cs b/Content.Client/State/GameScreen.cs index 3deb982aae..a0d947c4e8 100644 --- a/Content.Client/State/GameScreen.cs +++ b/Content.Client/State/GameScreen.cs @@ -1,13 +1,19 @@ +using System.Collections.Generic; +using System.Collections.Immutable; using Content.Client.Chat; using Content.Client.Interfaces.Chat; using Content.Client.UserInterface; using Content.Shared.Input; using Robust.Client.Interfaces.Input; +using Robust.Client.Interfaces.State; using Robust.Client.Interfaces.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; +using Robust.Shared.Map; using Robust.Shared.ViewVariables; namespace Content.Client.State @@ -41,6 +47,9 @@ namespace Content.Client.State _inputManager.SetInputCommand(ContentKeyFunctions.FocusChat, InputCmdHandler.FromDelegate(s => FocusChat(_gameChat))); + + _inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC, + InputCmdHandler.FromDelegate(s => FocusOOC(_gameChat))); } public override void Shutdown() @@ -61,5 +70,16 @@ namespace Content.Client.State chat.Input.IgnoreNext = true; chat.Input.GrabKeyboardFocus(); } + internal static void FocusOOC(ChatBox chat) + { + if (chat == null || chat.UserInterfaceManager.KeyboardFocused != null) + { + return; + } + + chat.Input.IgnoreNext = true; + chat.Input.GrabKeyboardFocus(); + chat.Input.InsertAtCursor("["); + } } } diff --git a/Content.Client/State/GameScreenBase.cs b/Content.Client/State/GameScreenBase.cs index b11201eca3..f7d7742540 100644 --- a/Content.Client/State/GameScreenBase.cs +++ b/Content.Client/State/GameScreenBase.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using Content.Client.GameObjects.Components; -using Content.Shared.GameObjects; using Content.Shared.GameObjects.EntitySystems; using Robust.Client.GameObjects.EntitySystems; using Robust.Client.Interfaces.GameObjects; @@ -9,6 +9,7 @@ using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.Interfaces.Graphics.ClientEye; using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.UserInterface; +using Robust.Client.Interfaces.State; using Robust.Client.Player; using Robust.Shared.GameObjects; using Robust.Shared.Input; @@ -71,7 +72,7 @@ namespace Content.Client.State .InRangeUnobstructed(playerPos, entityPos, predicate: entity => entity == _playerManager.LocalPlayer.ControlledEntity || entity == entityToClick, - insideBlockerValid: true); + ignoreInsideBlocker: true); } InteractionOutlineComponent outline; @@ -146,6 +147,25 @@ namespace Content.Client.State return foundEntities.Select(a => a.clicked).ToList(); } + /// + /// Gets all entities intersecting the given position. + /// + /// Static alternative to GetEntitiesUnderPosition to cut out + /// some of the boilerplate needed to get state manager and check the current state. + /// + /// state manager to use to get the current game screen + /// coordinates to check + /// the entities under the position, empty list if none found + public static IList GetEntitiesUnderPosition(IStateManager stateManager, GridCoordinates coordinates) + { + if (stateManager.CurrentState is GameScreenBase gameScreenBase) + { + return gameScreenBase.GetEntitiesUnderPosition(coordinates); + } + + return ImmutableList.Empty; + } + internal class ClickableEntityComparer : IComparer<(IEntity clicked, int depth, uint renderOrder)> { public int Compare((IEntity clicked, int depth, uint renderOrder) x, diff --git a/Content.Client/State/LobbyState.cs b/Content.Client/State/LobbyState.cs index 3209e1d01b..440509796c 100644 --- a/Content.Client/State/LobbyState.cs +++ b/Content.Client/State/LobbyState.cs @@ -12,6 +12,7 @@ using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Client.UserInterface.Controls; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; diff --git a/Content.Client/UserInterface/GameHud.cs b/Content.Client/UserInterface/GameHud.cs index fdfd3e624c..587dbe4304 100644 --- a/Content.Client/UserInterface/GameHud.cs +++ b/Content.Client/UserInterface/GameHud.cs @@ -9,6 +9,7 @@ using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Input; +using Robust.Shared.Input.Binding; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; diff --git a/Content.Client/UserInterface/HumanoidProfileEditor.cs b/Content.Client/UserInterface/HumanoidProfileEditor.cs index 83e0492885..7a6f5f33d4 100644 --- a/Content.Client/UserInterface/HumanoidProfileEditor.cs +++ b/Content.Client/UserInterface/HumanoidProfileEditor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.Components; @@ -6,6 +6,7 @@ using Content.Client.Interfaces; using Content.Client.Utility; using Content.Shared; using Content.Shared.Jobs; +using Content.Shared.Antags; using Content.Shared.Preferences; using Robust.Client.Graphics.Drawing; using Robust.Client.UserInterface; @@ -42,6 +43,7 @@ namespace Content.Client.UserInterface private readonly FacialHairStylePicker _facialHairPicker; private readonly List _jobPriorities; private readonly OptionButton _preferenceUnavailableButton; + private readonly List _antagPreferences; private bool _isDirty; public int CharacterSlot; @@ -320,6 +322,52 @@ namespace Content.Client.UserInterface #endregion + #region Antags + + { + var antagList = new VBoxContainer(); + + var antagVBox = new VBoxContainer + { + Children = + { + new ScrollContainer + { + SizeFlagsVertical = SizeFlags.FillExpand, + Children = + { + antagList + } + } + } + }; + + tabContainer.AddChild(antagVBox); + + tabContainer.SetTabTitle(2, Loc.GetString("Antags")); + + _antagPreferences = new List(); + + foreach (var antag in prototypeManager.EnumeratePrototypes().OrderBy(a => a.Name)) + { + if(!antag.SetPreference) + { + continue; + } + var selector = new AntagPreferenceSelector(antag); + antagList.AddChild(selector); + _antagPreferences.Add(selector); + + selector.PreferenceChanged += preference => + { + Profile = Profile.WithAntagPreference(antag.ID, preference); + IsDirty = true; + }; + } + } + + #endregion + var rightColumn = new VBoxContainer(); middleContainer.AddChild(rightColumn); @@ -466,6 +514,7 @@ namespace Content.Client.UserInterface UpdateHairPickers(); UpdateSaveButton(); UpdateJobPriorities(); + UpdateAntagPreferences(); _preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable); } @@ -533,5 +582,51 @@ namespace Content.Client.UserInterface }); } } + + private void UpdateAntagPreferences() + { + foreach (var preferenceSelector in _antagPreferences) + { + var antagId = preferenceSelector.Antag.ID; + + var preference = Profile.AntagPreferences.Contains(antagId); + + preferenceSelector.Preference = preference; + } + } + + private class AntagPreferenceSelector : Control + { + public AntagPrototype Antag { get; } + private readonly CheckBox _checkBox; + + public bool Preference + { + get => _checkBox.Pressed; + set => _checkBox.Pressed = value; + } + + public event Action PreferenceChanged; + + public AntagPreferenceSelector(AntagPrototype antag) + { + Antag = antag; + + _checkBox = new CheckBox {Text = $"{antag.Name}"}; + _checkBox.OnToggled += OnCheckBoxToggled; + + AddChild(new HBoxContainer + { + Children = + { + _checkBox + } + }); + } + private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args) + { + PreferenceChanged?.Invoke(Preference); + } + } } } diff --git a/Content.Client/UserInterface/TutorialWindow.cs b/Content.Client/UserInterface/TutorialWindow.cs index af54907d57..ce9362a62c 100644 --- a/Content.Client/UserInterface/TutorialWindow.cs +++ b/Content.Client/UserInterface/TutorialWindow.cs @@ -75,6 +75,7 @@ Open inventory: [color=#a4885c]{7}[/color] Open character window: [color=#a4885c]{8}[/color] Open crafting window: [color=#a4885c]{9}[/color] Focus chat: [color=#a4885c]{10}[/color] +Focus OOC: [color=#a4885c]{26}[/color] Use hand/object in hand: [color=#a4885c]{22}[/color] Do wide attack: [color=#a4885c]{23}[/color] Use targeted entity: [color=#a4885c]{11}[/color] @@ -110,7 +111,8 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]", Key(Use), Key(WideAttack), Key(SmartEquipBackpack), - Key(SmartEquipBelt))); + Key(SmartEquipBelt), + Key(FocusOOC))); //Gameplay VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" }); diff --git a/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.Designer.cs b/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.Designer.cs new file mode 100644 index 0000000000..266aa377e5 --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.Designer.cs @@ -0,0 +1,185 @@ +// +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Content.Server.Database.Migrations.Postgres +{ + [DbContext(typeof(PostgresPreferencesDbContext))] + [Migration("20200706172726_Antags")] + partial class Antags + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("AntagId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("text"); + + b.Property("HumanoidProfileId") + .HasColumnType("integer"); + + b.HasKey("AntagId"); + + b.HasIndex("HumanoidProfileId", "AntagName") + .IsUnique(); + + b.ToTable("Antag"); + }); + + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => + { + b.Property("HumanoidProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Age") + .HasColumnType("integer"); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("EyeColor") + .IsRequired() + .HasColumnType("text"); + + b.Property("FacialHairColor") + .IsRequired() + .HasColumnType("text"); + + b.Property("FacialHairName") + .IsRequired() + .HasColumnType("text"); + + b.Property("HairColor") + .IsRequired() + .HasColumnType("text"); + + b.Property("HairName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PreferenceUnavailable") + .HasColumnType("integer"); + + b.Property("PrefsId") + .HasColumnType("integer"); + + b.Property("Sex") + .IsRequired() + .HasColumnType("text"); + + b.Property("SkinColor") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("SlotName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("HumanoidProfileId"); + + b.HasIndex("PrefsId"); + + b.HasIndex("Slot", "PrefsId") + .IsUnique(); + + b.ToTable("HumanoidProfile"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property("JobId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("JobName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("ProfileHumanoidProfileId") + .HasColumnType("integer"); + + b.HasKey("JobId"); + + b.HasIndex("ProfileHumanoidProfileId"); + + b.ToTable("Job"); + }); + + modelBuilder.Entity("Content.Server.Database.Prefs", b => + { + b.Property("PrefsId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("SelectedCharacterSlot") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("PrefsId"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Antags") + .HasForeignKey("HumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => + { + b.HasOne("Content.Server.Database.Prefs", "Prefs") + .WithMany("HumanoidProfiles") + .HasForeignKey("PrefsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileHumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.cs b/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.cs new file mode 100644 index 0000000000..23d595a79b --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20200706172726_Antags.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Content.Server.Database.Migrations.Postgres +{ + public partial class Antags : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Antag", + columns: table => new + { + AntagId = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + HumanoidProfileId = table.Column(nullable: false), + AntagName = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Antag", x => x.AntagId); + table.ForeignKey( + name: "FK_Antag_HumanoidProfile_HumanoidProfileId", + column: x => x.HumanoidProfileId, + principalTable: "HumanoidProfile", + principalColumn: "HumanoidProfileId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Antag_HumanoidProfileId_AntagName", + table: "Antag", + columns: new[] { "HumanoidProfileId", "AntagName" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Antag"); + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/PostgresPreferencesDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Postgres/PostgresPreferencesDbContextModelSnapshot.cs index bfd4851099..0343886635 100644 --- a/Content.Server.Database/Migrations/Postgres/PostgresPreferencesDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Postgres/PostgresPreferencesDbContextModelSnapshot.cs @@ -18,6 +18,28 @@ namespace Content.Server.Database.Migrations.Postgres .HasAnnotation("ProductVersion", "3.1.4") .HasAnnotation("Relational:MaxIdentifierLength", 63); + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("AntagId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("text"); + + b.Property("HumanoidProfileId") + .HasColumnType("integer"); + + b.HasKey("AntagId"); + + b.HasIndex("HumanoidProfileId", "AntagName") + .IsUnique(); + + b.ToTable("Antag"); + }); + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => { b.Property("HumanoidProfileId") @@ -129,6 +151,15 @@ namespace Content.Server.Database.Migrations.Postgres b.ToTable("Preferences"); }); + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Antags") + .HasForeignKey("HumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => { b.HasOne("Content.Server.Database.Prefs", "Prefs") diff --git a/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.Designer.cs b/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.Designer.cs new file mode 100644 index 0000000000..00fe13a785 --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.Designer.cs @@ -0,0 +1,178 @@ +// +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Content.Server.Database.Migrations.Sqlite +{ + [DbContext(typeof(SqlitePreferencesDbContext))] + [Migration("20200706172741_Antags")] + partial class Antags + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.4"); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("AntagId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("HumanoidProfileId") + .HasColumnType("INTEGER"); + + b.HasKey("AntagId"); + + b.HasIndex("HumanoidProfileId", "AntagName") + .IsUnique(); + + b.ToTable("Antag"); + }); + + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => + { + b.Property("HumanoidProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Age") + .HasColumnType("INTEGER"); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("EyeColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FacialHairColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FacialHairName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("HairColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("HairName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PreferenceUnavailable") + .HasColumnType("INTEGER"); + + b.Property("PrefsId") + .HasColumnType("INTEGER"); + + b.Property("Sex") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SkinColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Slot") + .HasColumnType("INTEGER"); + + b.Property("SlotName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("HumanoidProfileId"); + + b.HasIndex("PrefsId"); + + b.HasIndex("Slot", "PrefsId") + .IsUnique(); + + b.ToTable("HumanoidProfile"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property("JobId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("JobName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Priority") + .HasColumnType("INTEGER"); + + b.Property("ProfileHumanoidProfileId") + .HasColumnType("INTEGER"); + + b.HasKey("JobId"); + + b.HasIndex("ProfileHumanoidProfileId"); + + b.ToTable("Job"); + }); + + modelBuilder.Entity("Content.Server.Database.Prefs", b => + { + b.Property("PrefsId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("SelectedCharacterSlot") + .HasColumnType("INTEGER"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PrefsId"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Antags") + .HasForeignKey("HumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => + { + b.HasOne("Content.Server.Database.Prefs", "Prefs") + .WithMany("HumanoidProfiles") + .HasForeignKey("PrefsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileHumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.cs b/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.cs new file mode 100644 index 0000000000..f2c1185b00 --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20200706172741_Antags.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Content.Server.Database.Migrations.Sqlite +{ + public partial class Antags : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Antag", + columns: table => new + { + AntagId = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + HumanoidProfileId = table.Column(nullable: false), + AntagName = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Antag", x => x.AntagId); + table.ForeignKey( + name: "FK_Antag_HumanoidProfile_HumanoidProfileId", + column: x => x.HumanoidProfileId, + principalTable: "HumanoidProfile", + principalColumn: "HumanoidProfileId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Antag_HumanoidProfileId_AntagName", + table: "Antag", + columns: new[] { "HumanoidProfileId", "AntagName" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Antag"); + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/SqlitePreferencesDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Sqlite/SqlitePreferencesDbContextModelSnapshot.cs index bf6e21f02a..60b7c39f14 100644 --- a/Content.Server.Database/Migrations/Sqlite/SqlitePreferencesDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Sqlite/SqlitePreferencesDbContextModelSnapshot.cs @@ -15,6 +15,27 @@ namespace Content.Server.Database.Migrations modelBuilder .HasAnnotation("ProductVersion", "3.1.4"); + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("AntagId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("HumanoidProfileId") + .HasColumnType("INTEGER"); + + b.HasKey("AntagId"); + + b.HasIndex("HumanoidProfileId", "AntagName") + .IsUnique(); + + b.ToTable("Antag"); + }); + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => { b.Property("HumanoidProfileId") @@ -123,6 +144,15 @@ namespace Content.Server.Database.Migrations b.ToTable("Preferences"); }); + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.HumanoidProfile", "Profile") + .WithMany("Antags") + .HasForeignKey("HumanoidProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b => { b.HasOne("Content.Server.Database.Prefs", "Prefs") diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index e3c62ffd13..a28d1dcb8f 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -64,6 +64,10 @@ namespace Content.Server.Database modelBuilder.Entity() .HasIndex(p => new {p.Slot, p.PrefsId}) .IsUnique(); + + modelBuilder.Entity() + .HasIndex(p => new {p.HumanoidProfileId , p.AntagName}) + .IsUnique(); } } @@ -90,6 +94,7 @@ namespace Content.Server.Database public string EyeColor { get; set; } = null!; public string SkinColor { get; set; } = null!; public List Jobs { get; } = new List(); + public List Antags { get; } = new List(); public DbPreferenceUnavailableMode PreferenceUnavailable { get; set; } public int PrefsId { get; set; } @@ -114,6 +119,15 @@ namespace Content.Server.Database High = 3 } + public class Antag + { + public int AntagId { get; set; } + public HumanoidProfile Profile { get; set; } = null!; + public int HumanoidProfileId { get; set; } + + public string AntagName { get; set; } = null!; + } + public enum DbPreferenceUnavailableMode { // These enum values HAVE to match the ones in PreferenceUnavailableMode in Shared. diff --git a/Content.Server.Database/PrefsDb.cs b/Content.Server.Database/PrefsDb.cs index a1c3de32cd..73e98b0216 100644 --- a/Content.Server.Database/PrefsDb.cs +++ b/Content.Server.Database/PrefsDb.cs @@ -26,8 +26,8 @@ namespace Content.Server.Database { return await _prefsCtx .Preferences - .Include(p => p.HumanoidProfiles) - .ThenInclude(h => h.Jobs) + .Include(p => p.HumanoidProfiles).ThenInclude(h => h.Jobs) + .Include(p => p.HumanoidProfiles).ThenInclude(h => h.Antags) .SingleOrDefaultAsync(p => p.Username == username); } @@ -72,6 +72,7 @@ namespace Content.Server.Database { return await _prefsCtx.HumanoidProfile .Include(p => p.Jobs) + .Include(a => a.Antags) .Join(_prefsCtx.Preferences, profile => new {profile.Slot, profile.PrefsId}, prefs => new {Slot = prefs.SelectedCharacterSlot, prefs.PrefsId}, diff --git a/Content.Server/AI/Operators/Combat/Melee/SwingMeleeWeaponOperator.cs b/Content.Server/AI/Operators/Combat/Melee/SwingMeleeWeaponOperator.cs index 38065d5973..207710d94b 100644 --- a/Content.Server/AI/Operators/Combat/Melee/SwingMeleeWeaponOperator.cs +++ b/Content.Server/AI/Operators/Combat/Melee/SwingMeleeWeaponOperator.cs @@ -2,6 +2,7 @@ using Content.Server.GameObjects; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -28,7 +29,7 @@ namespace Content.Server.AI.Operators.Combat.Melee { return true; } - + if (!_owner.TryGetComponent(out CombatModeComponent combatModeComponent)) { return false; @@ -41,7 +42,7 @@ namespace Content.Server.AI.Operators.Combat.Melee return true; } - + public override void Shutdown(Outcome outcome) { base.Shutdown(outcome); diff --git a/Content.Server/AI/Operators/Combat/Melee/UnarmedCombatOperator.cs b/Content.Server/AI/Operators/Combat/Melee/UnarmedCombatOperator.cs index 5fc0332351..a0bade8ae3 100644 --- a/Content.Server/AI/Operators/Combat/Melee/UnarmedCombatOperator.cs +++ b/Content.Server/AI/Operators/Combat/Melee/UnarmedCombatOperator.cs @@ -2,6 +2,7 @@ using Content.Server.GameObjects; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -29,7 +30,7 @@ namespace Content.Server.AI.Operators.Combat.Melee { return true; } - + if (!_owner.TryGetComponent(out CombatModeComponent combatModeComponent)) { return false; @@ -39,7 +40,7 @@ namespace Content.Server.AI.Operators.Combat.Melee { combatModeComponent.IsInCombatMode = true; } - + if (_owner.TryGetComponent(out UnarmedCombatComponent unarmedCombatComponent)) { _unarmedCombat = unarmedCombatComponent; @@ -85,4 +86,4 @@ namespace Content.Server.AI.Operators.Combat.Melee return Outcome.Continuing; } } -} \ No newline at end of file +} diff --git a/Content.Server/AI/Operators/Inventory/CloseStorageOperator.cs b/Content.Server/AI/Operators/Inventory/CloseStorageOperator.cs index 7822411274..d70300e4a4 100644 --- a/Content.Server/AI/Operators/Inventory/CloseStorageOperator.cs +++ b/Content.Server/AI/Operators/Inventory/CloseStorageOperator.cs @@ -1,8 +1,7 @@ using Content.Server.AI.Utility; using Content.Server.AI.WorldState.States.Inventory; using Content.Server.GameObjects.Components; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Robust.Shared.Interfaces.GameObjects; @@ -28,7 +27,7 @@ namespace Content.Server.AI.Operators.Inventory { return true; } - + var blackboard = UtilityAiHelpers.GetBlackboard(_owner); if (blackboard == null) @@ -37,7 +36,7 @@ namespace Content.Server.AI.Operators.Inventory } _target = blackboard.GetState().GetValue(); - + return _target != null; } @@ -56,12 +55,12 @@ namespace Content.Server.AI.Operators.Inventory return Outcome.Failed; } - if (!_target.TryGetComponent(out EntityStorageComponent storageComponent) || + if (!_target.TryGetComponent(out EntityStorageComponent storageComponent) || storageComponent.IsWeldedShut) { return Outcome.Failed; } - + if (storageComponent.Open) { var activateArgs = new ActivateEventArgs {User = _owner, Target = _target}; @@ -71,4 +70,4 @@ namespace Content.Server.AI.Operators.Inventory return Outcome.Success; } } -} \ No newline at end of file +} diff --git a/Content.Server/AI/Operators/Inventory/InteractWithEntityOperator.cs b/Content.Server/AI/Operators/Inventory/InteractWithEntityOperator.cs index dc2412a335..8e49c9587c 100644 --- a/Content.Server/AI/Operators/Inventory/InteractWithEntityOperator.cs +++ b/Content.Server/AI/Operators/Inventory/InteractWithEntityOperator.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; using Content.Server.Utility; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; diff --git a/Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs b/Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs index f90046ea45..54190e6e0b 100644 --- a/Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs +++ b/Content.Server/AI/Operators/Inventory/OpenStorageOperator.cs @@ -1,8 +1,7 @@ using Content.Server.AI.Utility; using Content.Server.AI.WorldState.States.Inventory; using Content.Server.GameObjects.Components; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.Containers; @@ -17,13 +16,13 @@ namespace Content.Server.AI.Operators.Inventory { private readonly IEntity _owner; private readonly IEntity _target; - + public OpenStorageOperator(IEntity owner, IEntity target) { _owner = owner; _target = target; } - + public override Outcome Execute(float frameTime) { if (!ContainerHelpers.TryGetContainer(_target, out var container)) @@ -36,22 +35,22 @@ namespace Content.Server.AI.Operators.Inventory return Outcome.Failed; } - if (!container.Owner.TryGetComponent(out EntityStorageComponent storageComponent) || + if (!container.Owner.TryGetComponent(out EntityStorageComponent storageComponent) || storageComponent.IsWeldedShut) { return Outcome.Failed; } - + if (!storageComponent.Open) { var activateArgs = new ActivateEventArgs {User = _owner, Target = _target}; storageComponent.Activate(activateArgs); } - + var blackboard = UtilityAiHelpers.GetBlackboard(_owner); blackboard?.GetState().SetValue(container.Owner); - + return Outcome.Success; } } -} \ No newline at end of file +} diff --git a/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs b/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs index b9f5cbb772..01255d9470 100644 --- a/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs +++ b/Content.Server/AI/Operators/Inventory/PickupEntityOperator.cs @@ -1,6 +1,5 @@ using Content.Server.GameObjects; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; using Content.Server.Utility; using Robust.Shared.Containers; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/AI/Operators/Inventory/UseItemInHandsOperator.cs b/Content.Server/AI/Operators/Inventory/UseItemInHandsOperator.cs index 2ccc6e23ab..f8af6d8970 100644 --- a/Content.Server/AI/Operators/Inventory/UseItemInHandsOperator.cs +++ b/Content.Server/AI/Operators/Inventory/UseItemInHandsOperator.cs @@ -31,7 +31,7 @@ namespace Content.Server.AI.Operators.Inventory return Outcome.Failed; } - if (_target.TryGetComponent(out ItemComponent itemComponent)) + if (!_target.TryGetComponent(out ItemComponent itemComponent)) { return Outcome.Failed; } diff --git a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs index 5d9949508e..0a1828d495 100644 --- a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs +++ b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs @@ -1,6 +1,8 @@ using Content.Server.AI.Utility.Curves; using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.EntitySystems; namespace Content.Server.AI.Utility.Considerations.ActionBlocker diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs index f36474ba1e..60c6eb4a64 100644 --- a/Content.Server/Chat/ChatManager.cs +++ b/Content.Server/Chat/ChatManager.cs @@ -1,6 +1,6 @@ using System.Linq; using Content.Server.GameObjects.Components.Observer; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Server.Observer; diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index c16c0fb636..b7220dc612 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -61,6 +61,7 @@ namespace Content.Server IoCManager.Resolve().StartInit(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); } public override void PostInit() @@ -69,7 +70,6 @@ namespace Content.Server IoCManager.Resolve().FinishInit(); _gameTicker.Initialize(); - IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); diff --git a/Content.Server/Explosions/ExplosionHelper.cs b/Content.Server/Explosions/ExplosionHelper.cs index a7a61a6396..44b8926b71 100644 --- a/Content.Server/Explosions/ExplosionHelper.cs +++ b/Content.Server/Explosions/ExplosionHelper.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Maps; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs index 6d38382cad..3f12ad5f47 100644 --- a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects; using Content.Server.Utility; diff --git a/Content.Server/GameObjects/Components/AnchorableComponent.cs b/Content.Server/GameObjects/Components/AnchorableComponent.cs index ef98de532a..ef8e0b4a27 100644 --- a/Content.Server/GameObjects/Components/AnchorableComponent.cs +++ b/Content.Server/GameObjects/Components/AnchorableComponent.cs @@ -1,5 +1,5 @@ -using Content.Server.GameObjects.Components.Interactable; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Interactable; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Interactable; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; diff --git a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs index b8be1cda01..cd5effccc2 100644 --- a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs @@ -1,6 +1,7 @@ using Content.Server.Cargo; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Cargo; using Content.Shared.Prototypes.Cargo; using JetBrains.Annotations; diff --git a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs index aa3fa3ea7b..189a7c3808 100644 --- a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs @@ -1,6 +1,6 @@ using System; using Content.Server.GameObjects.Components.Metabolism; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Utility; using Content.Shared.Chemistry; diff --git a/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs b/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs index 3d14e1c481..c23f727381 100644 --- a/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; using Content.Server.GameObjects.Components.Nutrition; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Utility; using Content.Shared.Chemistry; diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs index a79cda3136..aa3be1f5bc 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs @@ -2,7 +2,7 @@ using System.Linq; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Sound; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.GameObjects.Components.Power; using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs index 96b2dec4d7..c72c05f10c 100644 --- a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -1,5 +1,5 @@ using Content.Server.Chemistry; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Chemistry; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Chemistry; @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Linq; using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects.Systems; +using Content.Server.GameObjects.EntitySystems.Click; namespace Content.Server.GameObjects.Components.Chemistry { diff --git a/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs b/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs index 94d18c734e..048eb685a1 100644 --- a/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Chemistry; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs b/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs index 50db5f1ba3..38e54736b5 100644 --- a/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs @@ -1,6 +1,6 @@ using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameTicking; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Command; diff --git a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs index 1eb9cad50e..5005046472 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs @@ -1,4 +1,11 @@ -using Content.Shared.Construction; +using System; +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Interactable; +using Content.Server.GameObjects.Components.Stack; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Server.Interfaces; +using Content.Server.Utility; +using Content.Shared.Construction; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; diff --git a/Content.Server/GameObjects/Components/Damage/BreakableComponent.cs b/Content.Server/GameObjects/Components/Damage/BreakableComponent.cs index de784838c5..226abbc3ab 100644 --- a/Content.Server/GameObjects/Components/Damage/BreakableComponent.cs +++ b/Content.Server/GameObjects/Components/Damage/BreakableComponent.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs b/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs new file mode 100644 index 0000000000..8a50cd06c5 --- /dev/null +++ b/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs @@ -0,0 +1,68 @@ +using Content.Server.GameObjects.Components.Interactable; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Interactable; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using System.Collections.Generic; +using Content.Server.Interfaces.GameObjects.Components.Interaction; + +namespace Content.Server.GameObjects.Components.Damage +{ + [RegisterComponent] + class DamageOnToolInteractComponent : Component, IInteractUsing + { + public override string Name => "DamageOnToolInteract"; + + /* Set in YAML */ + protected int Damage; + private List _tools = new List(); + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref Damage, "damage", 0); + + serializer.DataField(ref _tools, "tools", new List()); + } + + public override void Initialize() + { + base.Initialize(); + Owner.EnsureComponent(); + } + + public bool InteractUsing(InteractUsingEventArgs eventArgs) + { + if (eventArgs.Using.TryGetComponent(out var tool)) + { + foreach (var toolQuality in _tools) + { + if (tool.HasQuality(ToolQuality.Welding) && toolQuality == ToolQuality.Welding) + { + if (eventArgs.Using.TryGetComponent(out WelderComponent welder)) + { + if (welder.WelderLit) return CallDamage(eventArgs, tool); + } + break; //If the tool quality is welding and its not lit or its not actually a welder that can be lit then its pointless to continue. + } + + if (tool.HasQuality(toolQuality)) return CallDamage(eventArgs, tool); + } + } + return false; + } + + protected bool CallDamage(InteractUsingEventArgs eventArgs, ToolComponent tool) + { + if (eventArgs.Target.TryGetComponent(out var damageable)) + { + if(tool.HasQuality(ToolQuality.Welding)) damageable.TakeDamage(Shared.GameObjects.DamageType.Heat, Damage, eventArgs.Using, eventArgs.User); + else + damageable.TakeDamage(Shared.GameObjects.DamageType.Brute, Damage, eventArgs.Using, eventArgs.User); + return true; + } + return false; + } + } +} diff --git a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs index ed72c17540..ae3fc6dcb2 100644 --- a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs +++ b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs index e5755e3c5b..339e235790 100644 --- a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs @@ -3,7 +3,7 @@ using System.Threading; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.VendingMachines; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects.Components.Doors; using Content.Shared.GameObjects.Components.Interactable; diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs index 0c424fe17d..50ea455972 100644 --- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs @@ -1,6 +1,8 @@ using System; using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Server.Utility; using Content.Shared.GameObjects.Components.Doors; using Content.Shared.GameObjects.Components.Movement; using Robust.Server.GameObjects; @@ -154,7 +156,7 @@ namespace Content.Server.GameObjects Timer.Spawn(OpenTimeOne, async () => { - collidableComponent.CanCollide = false; + collidableComponent.Hard = false; await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token); @@ -192,14 +194,14 @@ namespace Content.Server.GameObjects public bool Close() { - if (collidableComponent.IsColliding(Vector2.Zero)) + if (collidableComponent.IsColliding(Vector2.Zero, false)) { // Do nothing, somebody's in the door. return false; } State = DoorState.Closing; - collidableComponent.CanCollide = true; + collidableComponent.Hard = true; OpenTimeCounter = 0; SetAppearance(DoorVisualState.Closing); diff --git a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs index f23c611e24..96b7f19202 100644 --- a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs +++ b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs @@ -1,5 +1,5 @@ using Content.Server.Explosions; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; diff --git a/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs b/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs index f2538c200a..b0c59d6d24 100644 --- a/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs +++ b/Content.Server/GameObjects/Components/Explosion/FlashExplosiveComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Weapon; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -52,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Explosion { Owner.Delete(); } - + return true; } diff --git a/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs b/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs index 9eb7c71ad0..b35dd8d7b7 100644 --- a/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs @@ -1,7 +1,7 @@ using System; using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Sound; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Chemistry; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/Fluids/MopComponent.cs b/Content.Server/GameObjects/Components/Fluids/MopComponent.cs index 3cab561acb..22fc46878a 100644 --- a/Content.Server/GameObjects/Components/Fluids/MopComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/MopComponent.cs @@ -1,7 +1,7 @@ using System; using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Sound; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Chemistry; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 765c3aec4c..6091c504dc 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -2,9 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks.Dataflow; -using Content.Server.GameObjects.Components.Items.Clothing; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Content.Shared.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs index d770088292..899db7551e 100644 --- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs b/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs index a553c3e4bf..52f8a99fd5 100644 --- a/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs +++ b/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Gravity; diff --git a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs index bfebc2d3ab..b0d0b9e2c0 100644 --- a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs +++ b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Stack; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs index 868a74465e..d0017971e5 100644 --- a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Mobs; using Content.Shared.GameObjects.Components.Instruments; diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index f2f4f428a9..ca01e00419 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -1,4 +1,7 @@ using Content.Server.GameObjects.Components.Power; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs b/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs index e548f6e957..95973aa1d4 100644 --- a/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Interactable; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs b/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs index be625da60f..12f95f4371 100644 --- a/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.Maps; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs index bfa1ac94ee..495fc008b5 100644 --- a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs @@ -3,6 +3,11 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs index a820114876..bf55f988fa 100644 --- a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.Remoting; using Content.Server.GameObjects.Components.Chemistry; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs index 54778eb200..6bf0ae5822 100644 --- a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs @@ -3,18 +3,17 @@ using Robust.Shared.Utility; using System; using System.Collections.Generic; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; +using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.Components.Items.Clothing +namespace Content.Server.GameObjects { [RegisterComponent] [ComponentReference(typeof(ItemComponent))] diff --git a/Content.Server/GameObjects/Components/Items/DiceComponent.cs b/Content.Server/GameObjects/Components/Items/DiceComponent.cs index 9620c8bbd5..90f5ab03ce 100644 --- a/Content.Server/GameObjects/Components/Items/DiceComponent.cs +++ b/Content.Server/GameObjects/Components/Items/DiceComponent.cs @@ -1,5 +1,6 @@ -using Content.Server.GameObjects.Components.Sound; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Audio; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs index cc1ce34725..3ebd014501 100644 --- a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Stack; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Maps; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index 794fe1b35f..e6b0501ece 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -1,4 +1,8 @@ -using Content.Server.GameObjects.EntitySystems; +using System; +using Content.Server.GameObjects.Components; +using Content.Server.GameObjects.Components.Destructible; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Server.Throw; using Content.Server.Utility; @@ -89,7 +93,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage var userPos = user.Transform.MapPosition; var itemPos = Owner.Transform.MapPosition; - return InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, insideBlockerValid:true); + return InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, ignoreInsideBlocker:true); } public bool InteractHand(InteractHandEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs index 9f583e5a09..dbdb37c09e 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Access; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Storage; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index f5794eebd1..5ab57cdc29 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -1,8 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects; +using Content.Server.Utility; using Content.Shared.GameObjects.Components.Storage; using Content.Shared.Interfaces; using Robust.Server.GameObjects; @@ -18,10 +22,11 @@ using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Log; +using Robust.Shared.Maths; using Robust.Shared.Players; using Robust.Shared.Serialization; -namespace Content.Server.GameObjects.Components.Items.Storage +namespace Content.Server.GameObjects { /// /// Storage component for containing entities within this one, matches a UI on the client which shows stored entities @@ -29,7 +34,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage [RegisterComponent] [ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IStorageComponent))] - public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct + public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct, + IDragDrop { #pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager; @@ -406,5 +412,26 @@ namespace Content.Server.GameObjects.Components.Items.Storage Owner.PopupMessage(player, "Can't insert."); return false; } + + public bool DragDrop(DragDropEventArgs eventArgs) + { + if (eventArgs.Target.TryGetComponent(out var placeableSurface)) + { + if (!placeableSurface.IsPlaceable) return false; + + // empty everything out + foreach (var storedEntity in StoredEntities.ToList()) + { + if (Remove(storedEntity)) + { + storedEntity.Transform.WorldPosition = eventArgs.DropLocation.Position; + } + } + + return true; + } + + return false; + } } } diff --git a/Content.Server/GameObjects/Components/Items/ToysComponent.cs b/Content.Server/GameObjects/Components/Items/ToysComponent.cs index fdbf4d3347..d6ad2a8ae8 100644 --- a/Content.Server/GameObjects/Components/Items/ToysComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ToysComponent.cs @@ -1,5 +1,6 @@ using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Audio; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs index 719cfa813a..4bb9b23955 100644 --- a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs +++ b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.ViewVariables; diff --git a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs index 76017269c8..eec3bea3d3 100644 --- a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs +++ b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs b/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs index 05ed281f67..232ba77ccf 100644 --- a/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs +++ b/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Serialization; diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs index f8bbdaa168..84bd1b53ba 100644 --- a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Medical; using Content.Server.GameObjects.Components.Power; diff --git a/Content.Server/GameObjects/Components/Metabolism/BloodstreamComponent.cs b/Content.Server/GameObjects/Components/Metabolism/BloodstreamComponent.cs index e428c72f17..f1f9656f4f 100644 --- a/Content.Server/GameObjects/Components/Metabolism/BloodstreamComponent.cs +++ b/Content.Server/GameObjects/Components/Metabolism/BloodstreamComponent.cs @@ -1,6 +1,6 @@ using System.Linq; using Content.Server.GameObjects.Components.Chemistry; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Chemistry; using Robust.Shared.GameObjects; using Robust.Shared.IoC; diff --git a/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs b/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs index ef85c5eb4b..d6df7cca1d 100644 --- a/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs +++ b/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs @@ -1,6 +1,6 @@ using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Weapon.Melee; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Mobs/BuckleComponent.cs b/Content.Server/GameObjects/Components/Mobs/BuckleComponent.cs index 5f41dc90b7..bfda8318d6 100644 --- a/Content.Server/GameObjects/Components/Mobs/BuckleComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/BuckleComponent.cs @@ -2,6 +2,7 @@ using Content.Server.GameObjects.Components.Strap; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Mobs; using Content.Server.Utility; using Content.Shared.GameObjects; @@ -22,7 +23,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Mobs { [RegisterComponent] - public class BuckleComponent : SharedBuckleComponent, IInteractHand + public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop { #pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystem = default!; @@ -305,6 +306,11 @@ namespace Content.Server.GameObjects.Components.Mobs return TryUnbuckle(eventArgs.User); } + bool IDragDrop.DragDrop(DragDropEventArgs eventArgs) + { + return TryBuckle(eventArgs.User, eventArgs.Target); + } + [Verb] private sealed class BuckleVerb : Verb { diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index abfdcb52f0..ad79a7a106 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Mobs; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Mobs; diff --git a/Content.Server/GameObjects/Components/Mobs/DamageThresholdTemplates/HumanTemplate.cs b/Content.Server/GameObjects/Components/Mobs/DamageThresholdTemplates/HumanTemplate.cs index 18a93231da..d800514df1 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageThresholdTemplates/HumanTemplate.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageThresholdTemplates/HumanTemplate.cs @@ -69,21 +69,24 @@ namespace Content.Server.GameObjects statusEffectsComponent?.ChangeStatusEffectIcon(StatusEffect.Health, "/Textures/Mob/UI/Human/human" + modifier + ".png"); - overlayComponent?.ChangeOverlay(ScreenEffects.None); + overlayComponent?.RemoveOverlay(OverlayType.GradientCircleMaskOverlay); + overlayComponent?.RemoveOverlay(OverlayType.CircleMaskOverlay); return; case ThresholdType.Critical: statusEffectsComponent?.ChangeStatusEffectIcon( StatusEffect.Health, "/Textures/Mob/UI/Human/humancrit-0.png"); - overlayComponent?.ChangeOverlay(ScreenEffects.GradientCircleMask); + overlayComponent?.ClearOverlays(); + overlayComponent?.AddOverlay(OverlayType.GradientCircleMaskOverlay); return; case ThresholdType.Death: statusEffectsComponent?.ChangeStatusEffectIcon( StatusEffect.Health, "/Textures/Mob/UI/Human/humandead.png"); - overlayComponent?.ChangeOverlay(ScreenEffects.CircleMask); + overlayComponent?.ClearOverlays(); + overlayComponent?.AddOverlay(OverlayType.CircleMaskOverlay); return; default: diff --git a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs index 6272bc8464..3e15cdceaf 100644 --- a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs @@ -1,5 +1,6 @@ using Content.Server.GameObjects.Components.Observer; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameTicking; using Content.Server.Mobs; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs b/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs index 8cfcb33cb8..92c0b2d5d5 100644 --- a/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs @@ -1,5 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; using Content.Shared.GameObjects.Components.Mobs; using Robust.Shared.GameObjects; +using Robust.Shared.Timers; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Mobs { @@ -7,20 +12,49 @@ namespace Content.Server.GameObjects.Components.Mobs [ComponentReference(typeof(SharedOverlayEffectsComponent))] public sealed class ServerOverlayEffectsComponent : SharedOverlayEffectsComponent { - private ScreenEffects _currentOverlay = ScreenEffects.None; + private readonly List _currentOverlays = new List(); + + [ViewVariables(VVAccess.ReadWrite)] + private List ActiveOverlays => _currentOverlays; public override ComponentState GetComponentState() { - return new OverlayEffectComponentState(_currentOverlay); + return new OverlayEffectComponentState(_currentOverlays); } - public void ChangeOverlay(ScreenEffects effect) + public void AddOverlay(OverlayContainer container) { - if (effect == _currentOverlay) + if (!ActiveOverlays.Contains(container)) { - return; + ActiveOverlays.Add(container); + Dirty(); } - _currentOverlay = effect; + } + + public void AddOverlay(string id) => AddOverlay(new OverlayContainer(id)); + public void AddOverlay(OverlayType type) => AddOverlay(new OverlayContainer(type)); + + public void RemoveOverlay(OverlayContainer container) + { + if (ActiveOverlays.RemoveAll(c => c.Equals(container)) > 0) + { + Dirty(); + } + } + + public void RemoveOverlay(string id) + { + if (ActiveOverlays.RemoveAll(container => container.ID == id) > 0) + { + Dirty(); + } + } + + public void RemoveOverlay(OverlayType type) => RemoveOverlay(type.ToString()); + + public void ClearOverlays() + { + ActiveOverlays.Clear(); Dirty(); } } diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs index 380f93d667..ed64d334b6 100644 --- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Observer; using Content.Shared.GameObjects; @@ -79,7 +79,7 @@ namespace Content.Server.GameObjects statusEffectsComponent?.RemoveStatusEffect(StatusEffect.Health); Owner.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent); - overlayEffectsComponent?.ChangeOverlay(ScreenEffects.None); + overlayEffectsComponent?.ClearOverlays(); } bool IActionBlocker.CanMove() diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 3098310a57..0b72696503 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -1,5 +1,8 @@ using System; using System.Threading; +using Content.Server.GameObjects.Components.Movement; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Server.Interfaces.GameObjects; using Content.Server.GameObjects.EntitySystems; using Content.Server.Mobs; using Content.Shared.Audio; diff --git a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs index f6aaaf46da..12e55c9576 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Movement; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs index 00a1d32561..ef3dc7aaf1 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects.Components.NodeContainer.Nodes; +using Robust.Shared.IoC; using Robust.Shared.ViewVariables; using System.Collections.Generic; @@ -10,7 +11,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups /// public interface INodeGroup { - public IReadOnlyList Nodes { get; } + IReadOnlyList Nodes { get; } void AddNode(Node node); @@ -25,6 +26,8 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups void BeforeRemakeSpread(); void AfterRemakeSpread(); + + void RemakeGroup(); } [NodeGroup(NodeGroupID.Default)] @@ -49,7 +52,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups { _nodes.Remove(node); OnRemoveNode(node); - RemakeGroup(); + IoCManager.Resolve().AddDirtyNodeGroup(this); } public void CombineGroup(INodeGroup newGroup) @@ -73,7 +76,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups /// Causes all s to remake their groups. Called when a is removed /// and may have split a group in two, so multiple new groups may need to be formed. /// - private void RemakeGroup() + public void RemakeGroup() { BeforeRemake(); foreach (var node in Nodes) @@ -116,6 +119,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups public void AfterCombine() { } public void BeforeRemakeSpread() { } public void AfterRemakeSpread() { } + public void RemakeGroup() { } } } } diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs new file mode 100644 index 0000000000..762752fb78 --- /dev/null +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups +{ + /// + /// Maintains a set of s that need to be remade with . + /// Defers remaking to reduce recalculations when a group is altered multiple times in a frame. + /// + public interface INodeGroupManager + { + /// + /// Queue up an to be remade. + /// + void AddDirtyNodeGroup(INodeGroup nodeGroup); + + void Update(float frameTime); + } + + public class NodeGroupManager : INodeGroupManager + { + private readonly HashSet _dirtyNodeGroups = new HashSet(); + + public void AddDirtyNodeGroup(INodeGroup nodeGroup) + { + _dirtyNodeGroups.Add(nodeGroup); + } + + public void Update(float frameTime) + { + foreach (var group in _dirtyNodeGroups) + { + group.RemakeGroup(); + } + _dirtyNodeGroups.Clear(); + } + } +} diff --git a/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs b/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs index 82b1b25950..b0e6cefc40 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs @@ -72,7 +72,6 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes _deleting = true; if (Owner.TryGetComponent(out var physics)) { - AnchorUpdate(); physics.AnchoredChanged -= AnchorUpdate; } NodeGroup.RemoveNode(this); diff --git a/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs b/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs index 79081b27db..38d6e1fffe 100644 --- a/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs @@ -1,6 +1,7 @@ using System; using Content.Server.GameObjects.Components.Chemistry; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Nutrition; @@ -128,6 +129,7 @@ namespace Content.Server.GameObjects.Components.Nutrition if (!_opened) { target.PopupMessage(target, Loc.GetString("Open it first!")); + return false; } if (_contents.CurrentVolume.Float() <= 0) diff --git a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs index 2c71cb0ca8..f06c6d8d6b 100644 --- a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs @@ -5,6 +5,8 @@ using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Utensil; using Content.Server.GameObjects.EntitySystems; using Content.Server.Utility; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Utensil; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/Nutrition/FoodContainerComponent.cs b/Content.Server/GameObjects/Components/Nutrition/FoodContainerComponent.cs index 7891d77876..572f1963c5 100644 --- a/Content.Server/GameObjects/Components/Nutrition/FoodContainerComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/FoodContainerComponent.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Nutrition; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs index 9caca4a53c..ba906a1b78 100644 --- a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs +++ b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Players; using Content.Shared.GameObjects.Components.Observer; using Content.Shared.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs index bf0233776b..eb7f1d1b68 100644 --- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -3,8 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Access; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Interfaces.PDA; using Content.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs index 1cb46cece3..d8d391b483 100644 --- a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs +++ b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs index 1f8789d579..1f193bf5bd 100644 --- a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs +++ b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs @@ -1,15 +1,14 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; +using Content.Shared.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components { [RegisterComponent] - public class PlaceableSurfaceComponent : Component, IInteractUsing + public class PlaceableSurfaceComponent : SharedPlaceableSurfaceComponent, IInteractUsing { - public override string Name => "PlaceableSurface"; - private bool _isPlaceable; public bool IsPlaceable { get => _isPlaceable; set => _isPlaceable = value; } diff --git a/Content.Server/GameObjects/Components/PottedPlantHideComponent.cs b/Content.Server/GameObjects/Components/PottedPlantHideComponent.cs index cde1b10a6d..5de2091e62 100644 --- a/Content.Server/GameObjects/Components/PottedPlantHideComponent.cs +++ b/Content.Server/GameObjects/Components/PottedPlantHideComponent.cs @@ -1,5 +1,4 @@ -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects; using Content.Shared.Audio; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs index 9d7cebc0fb..5b5c62b12a 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs @@ -11,6 +11,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.ViewVariables; using System; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.IoC; using Robust.Shared.Interfaces.Timing; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs index 63e223dbb5..9a8002681d 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.EntitySystems; @@ -105,7 +106,7 @@ namespace Content.Server.GameObjects.Components.Power.Chargers { batteryBarrelComponent.UpdateAppearance(); } - + UpdateStatus(); } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs index 62742bb113..07aafe6459 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs @@ -1,5 +1,5 @@ using System; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs index ba066745d3..8e4adfced8 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs index 6a8df86157..404ea4d85d 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs @@ -2,6 +2,7 @@ using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Sound; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Server.Utility; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs index 4257742afa..bbbb29375a 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs @@ -1,5 +1,6 @@ using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs index 954dc1bcec..24270c597e 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs @@ -1,11 +1,11 @@ -using Content.Server.GameObjects.Components.Power.ApcNetComponents; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameTicking; using Content.Shared.GameObjects.Components.Power; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; -using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs index 7884358cfe..4cb7cde036 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs @@ -1,5 +1,6 @@ using System; using Content.Server.GameObjects.Components.Damage; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.GameObjects.Components.Power.PowerNetComponents; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Audio; diff --git a/Content.Server/GameObjects/Components/Power/WireComponent.cs b/Content.Server/GameObjects/Components/Power/WireComponent.cs index dce421d617..70b7d81193 100644 --- a/Content.Server/GameObjects/Components/Power/WireComponent.cs +++ b/Content.Server/GameObjects/Components/Power/WireComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Interactable; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; diff --git a/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs b/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs index 323abcf8c5..b23a3cbf90 100644 --- a/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.Components.Stack; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs index 1f5600b186..357724ba53 100644 --- a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs @@ -1,5 +1,6 @@ -using Content.Server.GameObjects.Components.Projectiles; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Projectiles; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.Physics; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Research/LatheComponent.cs b/Content.Server/GameObjects/Components/Research/LatheComponent.cs index bc6f16ac72..639664bdfa 100644 --- a/Content.Server/GameObjects/Components/Research/LatheComponent.cs +++ b/Content.Server/GameObjects/Components/Research/LatheComponent.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Stack; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Materials; using Content.Shared.GameObjects.Components.Power; diff --git a/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs index ad63bb4bb7..3f14fe00da 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Research; using Robust.Server.GameObjects.Components.UserInterface; diff --git a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs index 6bef26d671..2a2c8ce62c 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs @@ -1,6 +1,6 @@ using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Research; diff --git a/Content.Server/GameObjects/Components/Research/ResearchPointSourceComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchPointSourceComponent.cs index b273e41c26..c6d60cbd8a 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchPointSourceComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchPointSourceComponent.cs @@ -1,6 +1,6 @@ using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; diff --git a/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs index 148663a380..4060b01368 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Research; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; diff --git a/Content.Server/GameObjects/Components/Sound/EmitSoundOnThrowComponent.cs b/Content.Server/GameObjects/Components/Sound/EmitSoundOnThrowComponent.cs index 19d6f81922..25b0f149f5 100644 --- a/Content.Server/GameObjects/Components/Sound/EmitSoundOnThrowComponent.cs +++ b/Content.Server/GameObjects/Components/Sound/EmitSoundOnThrowComponent.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Audio; diff --git a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent.cs b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent.cs index e81c57a7df..ef6f330ffc 100644 --- a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent.cs +++ b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Audio; diff --git a/Content.Server/GameObjects/Components/Stack/StackComponent.cs b/Content.Server/GameObjects/Components/Stack/StackComponent.cs index 3db7729d5c..3d6d18d46d 100644 --- a/Content.Server/GameObjects/Components/Stack/StackComponent.cs +++ b/Content.Server/GameObjects/Components/Stack/StackComponent.cs @@ -1,5 +1,6 @@ using System; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components; using Content.Shared.Interfaces; diff --git a/Content.Server/GameObjects/Components/Strap/StrapComponent.cs b/Content.Server/GameObjects/Components/Strap/StrapComponent.cs index 32960ce041..d1584efe16 100644 --- a/Content.Server/GameObjects/Components/Strap/StrapComponent.cs +++ b/Content.Server/GameObjects/Components/Strap/StrapComponent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Strap; using Content.Shared.GameObjects.EntitySystems; @@ -35,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Strap public override StrapPosition Position { get => _position; - set + protected set { _position = value; Dirty(); @@ -157,6 +157,11 @@ namespace Content.Server.GameObjects.Components.Strap OccupiedSize = 0; } + public override ComponentState GetComponentState() + { + return new StrapComponentState(Position); + } + bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { if (!eventArgs.User.TryGetComponent(out BuckleComponent buckle)) diff --git a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs index 19d77f4ad7..81657b1063 100644 --- a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs +++ b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs @@ -1,5 +1,5 @@ using System; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Triggers; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Utensil/UtensilComponent.cs b/Content.Server/GameObjects/Components/Utensil/UtensilComponent.cs index 3069bd72c3..797a2160d9 100644 --- a/Content.Server/GameObjects/Components/Utensil/UtensilComponent.cs +++ b/Content.Server/GameObjects/Components/Utensil/UtensilComponent.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Nutrition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Utensil; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs b/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs index 4f730b77dd..6473490d56 100644 --- a/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs +++ b/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Power; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components.VendingMachines; using Content.Shared.VendingMachines; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs new file mode 100644 index 0000000000..e5c20ae24a --- /dev/null +++ b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.Interfaces; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; +using Timer = Robust.Shared.Timers.Timer; + +namespace Content.Server.GameObjects.Components.Weapon.Melee +{ + [RegisterComponent] + public class FlashComponent : MeleeWeaponComponent, IUse, IExamine + { +#pragma warning disable 649 + [Dependency] private readonly ILocalizationManager _localizationManager; + [Dependency] private readonly IEntityManager _entityManager; + [Dependency] private readonly ISharedNotifyManager _notifyManager; +#pragma warning restore 649 + + public override string Name => "Flash"; + + [ViewVariables(VVAccess.ReadWrite)] private int _flashDuration = 5000; + [ViewVariables(VVAccess.ReadWrite)] private float _flashFalloffExp = 8f; + [ViewVariables(VVAccess.ReadWrite)] private int _uses = 5; + [ViewVariables(VVAccess.ReadWrite)] private float _range = 3f; + [ViewVariables(VVAccess.ReadWrite)] private int _aoeFlashDuration = 5000 / 3; + [ViewVariables(VVAccess.ReadWrite)] private float _slowTo = 0.75f; + private bool _flashing; + + private int Uses + { + get => _uses; + set + { + _uses = value; + Dirty(); + } + } + + private bool HasUses => _uses > 0; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _flashDuration, "duration", 5000); + serializer.DataField(ref _flashFalloffExp, "flashFalloffExp", 8f); + serializer.DataField(ref _uses, "uses", 5); + serializer.DataField(ref _range, "range", 3f); + serializer.DataField(ref _aoeFlashDuration, "aoeFlashDuration", _flashDuration / 3); + serializer.DataField(ref _slowTo, "slowTo", 0.75f); + } + + protected override bool OnHitEntities(IReadOnlyList entities, AttackEventArgs eventArgs) + { + if (entities.Count == 0) + { + return false; + } + + if (!Use(eventArgs.User)) + { + return false; + } + + foreach (var entity in entities) + { + Flash(entity, eventArgs.User); + } + + return true; + } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + if (!Use(eventArgs.User)) + { + return false; + } + + foreach (var entity in _entityManager.GetEntitiesInRange(Owner.Transform.GridPosition, _range)) + { + Flash(entity, eventArgs.User, _aoeFlashDuration); + } + + return true; + } + + private bool Use(IEntity user) + { + if (HasUses) + { + var sprite = Owner.GetComponent(); + if (--Uses == 0) + { + sprite.LayerSetState(0, "burnt"); + + _notifyManager.PopupMessage(Owner, user, "The flash burns out!"); + } + else if (!_flashing) + { + int animLayer = sprite.AddLayerWithState("flashing"); + _flashing = true; + + Timer.Spawn(400, () => + { + sprite.RemoveLayer(animLayer); + _flashing = false; + }); + } + + EntitySystem.Get().PlayAtCoords("/Audio/weapons/flash.ogg", Owner.Transform.GridPosition, + AudioParams.Default); + + return true; + } + + return false; + } + + private void Flash(IEntity entity, IEntity user) + { + Flash(entity, user, _flashDuration); + } + + // TODO: Check if target can be flashed (e.g. things like sunglasses would block a flash) + private void Flash(IEntity entity, IEntity user, int flashDuration) + { + if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) + { + var container = new TimedOverlayContainer(nameof(OverlayType.FlashOverlay), flashDuration); + overlayEffectsComponent.AddOverlay(container); + container.StartTimer(() => overlayEffectsComponent.RemoveOverlay(container)); + } + + if (entity.TryGetComponent(out StunnableComponent stunnableComponent)) + { + stunnableComponent.Slowdown(flashDuration / 1000f, _slowTo, _slowTo); + } + + if (entity != user) + { + _notifyManager.PopupMessage(user, entity, $"{user.Name} blinds you with the {Owner.Name}"); + } + } + + public void Examine(FormattedMessage message, bool inDetailsRange) + { + if (!HasUses) + { + message.AddText("It's burnt out."); + return; + } + + if (inDetailsRange) + { + message.AddMarkup(_localizationManager.GetString( + $"The flash has [color=green]{Uses}[/color] uses remaining.")); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index 78fae35837..121d755527 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; using Robust.Server.GameObjects.EntitySystems; @@ -81,9 +81,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee serializer.DataField(ref _cooldownTime, "cooldownTime", 1f); } - public virtual bool OnHitEntities(IReadOnlyList entities) + protected virtual bool OnHitEntities(IReadOnlyList entities, AttackEventArgs eventArgs) { - return false; + return true; } void IAttack.Attack(AttackEventArgs eventArgs) @@ -112,7 +112,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee } } - if(OnHitEntities(hitEntities)) return; + if(!OnHitEntities(hitEntities, eventArgs)) return; var audioSystem = EntitySystem.Get(); var emitter = hitEntities.Count == 0 ? eventArgs.User : hitEntities[0]; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 29635e4a3d..b0a85bebbe 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -2,7 +2,8 @@ using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects; using Content.Shared.Audio; using Content.Shared.GameObjects; @@ -86,7 +87,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee serializer.DataField(ref _slowdownTime, "slowdownTime", 5f); } - public override bool OnHitEntities(IReadOnlyList entities) + protected override bool OnHitEntities(IReadOnlyList entities, AttackEventArgs eventArgs) { var cell = Cell; if (!Activated || entities.Count == 0 || cell == null) @@ -118,7 +119,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee TurnOff(); } - return false; + return true; } private bool ToggleStatus(IEntity user) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs index ba83be2675..88cd3ab9f9 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/RangedMagazineComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/RangedMagazineComponent.cs index 132879d104..e1cfe71da7 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/RangedMagazineComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/RangedMagazineComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.Interfaces; @@ -33,7 +34,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition public int ShotsLeft => _spawnedAmmo.Count + _unspawnedCount; public int Capacity => _capacity; private int _capacity; - + public MagazineType MagazineType => _magazineType; private MagazineType _magazineType; public BallisticCaliber Caliber => _caliber; @@ -88,7 +89,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition { _appearanceComponent = appearanceComponent; } - + _appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, true); } @@ -97,7 +98,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition _appearanceComponent?.SetData(AmmoVisuals.AmmoCount, ShotsLeft); _appearanceComponent?.SetData(AmmoVisuals.AmmoMax, Capacity); } - + public bool TryInsertAmmo(IEntity user, IEntity ammo) { if (!ammo.TryGetComponent(out AmmoComponent ammoComponent)) @@ -137,7 +138,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition _unspawnedCount--; ammo = Owner.EntityManager.SpawnEntity(_fillPrototype, Owner.Transform.GridPosition); } - + UpdateAppearance(); return ammo; } diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs index 4a427ca172..2a078a1ce9 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.Interfaces; using Robust.Server.GameObjects; @@ -39,7 +40,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition serializer.DataField(ref _caliber, "caliber", BallisticCaliber.Unspecified); serializer.DataField(ref _capacity, "capacity", 6); serializer.DataField(ref _fillPrototype, "fillPrototype", null); - + _spawnedAmmo = new Stack(_capacity); } @@ -57,7 +58,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition } } } - + void IMapInit.MapInit() { _unspawnedCount += _capacity; @@ -92,7 +93,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition Owner.PopupMessage(user, Loc.GetString("No room")); return false; } - + _spawnedAmmo.Push(entity); _ammoContainer.Insert(entity); UpdateAppearance(); @@ -150,10 +151,10 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition { return; } - + // This area is dirty but not sure of an easier way to do it besides add an interface or somethin bool changed = false; - + if (eventArgs.Target.TryGetComponent(out RevolverBarrelComponent revolverBarrel)) { for (var i = 0; i < Capacity; i++) @@ -194,9 +195,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition TryInsertAmmo(eventArgs.User, ammo); break; } - + } - + if (changed) { UpdateAppearance(); @@ -213,4 +214,4 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition return UseEntity(eventArgs.User); } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs index bdee4823b6..6ee38d4337 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/PumpBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/PumpBarrelComponent.cs index 405214490c..5116f2db5f 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/PumpBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/PumpBarrelComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.Interfaces; using Robust.Server.GameObjects; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs index 1bbd687df2..3d07ecfe18 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs @@ -2,6 +2,7 @@ using System; using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs index 9ed5d5bd4e..ac42c5cbf5 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs @@ -5,6 +5,7 @@ using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Projectiles; using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Robust.Server.GameObjects; @@ -69,9 +70,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels return (int) Math.Ceiling((float) (powerCell.GetComponent().MaxCharge / _baseFireCost)); } } - + private AppearanceComponent _appearanceComponent; - + // Sounds private string _soundPowerCellInsert; private string _soundPowerCellEject; @@ -111,10 +112,10 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { _appearanceComponent = appearanceComponent; } - + UpdateAppearance(); } - + public void UpdateAppearance() { _appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, _powerCellContainer.ContainedEntity != null); @@ -224,14 +225,14 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return null; } - + var entity = _powerCellContainer.ContainedEntity; _powerCellContainer.Remove(entity); if (_soundPowerCellEject != null) { EntitySystem.Get().PlayAtCoords(_soundPowerCellEject, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2)); } - + UpdateAppearance(); //Dirty(); return entity; @@ -243,8 +244,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return false; } - - if (!eventArgs.User.TryGetComponent(out HandsComponent handsComponent) || + + if (!eventArgs.User.TryGetComponent(out HandsComponent handsComponent) || PowerCellEntity == null) { return false; @@ -255,7 +256,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return false; } - + var powerCell = RemovePowerCell(); handsComponent.PutInHand(itemComponent); powerCell.Transform.GridPosition = eventArgs.User.Transform.GridPosition; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs index 1fed59e10b..4eff5981bf 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs index d074bb2ee9..dcf5af0083 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs @@ -5,6 +5,7 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Projectiles; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Weapons.Ranged; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs index c6cb930c1a..6ac04ed143 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs @@ -2,6 +2,7 @@ using System; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.GameObjects.Components.Weapons.Ranged; using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/WiresComponent.cs b/Content.Server/GameObjects/Components/WiresComponent.cs index 60d0dd0dc0..c1d91359a5 100644 --- a/Content.Server/GameObjects/Components/WiresComponent.cs +++ b/Content.Server/GameObjects/Components/WiresComponent.cs @@ -3,7 +3,8 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.VendingMachines; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.Click; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects.Components; diff --git a/Content.Server/GameObjects/EntitySystems/ActSystem.cs b/Content.Server/GameObjects/EntitySystems/ActSystem.cs index 56be8389ea..4fd95bb847 100644 --- a/Content.Server/GameObjects/EntitySystems/ActSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ActSystem.cs @@ -5,7 +5,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// This interface gives components behavior on getting destoyed. diff --git a/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs b/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs index 6e0415b6a9..7e59153404 100644 --- a/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] internal class BaseChargerSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/BloodstreamSystem.cs b/Content.Server/GameObjects/EntitySystems/BloodstreamSystem.cs index 7806e09b25..69b432084b 100644 --- a/Content.Server/GameObjects/EntitySystems/BloodstreamSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/BloodstreamSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// Triggers metabolism updates for diff --git a/Content.Server/GameObjects/EntitySystems/ChemistrySystem.cs b/Content.Server/GameObjects/EntitySystems/ChemistrySystem.cs index 69bd555460..39cca2be0e 100644 --- a/Content.Server/GameObjects/EntitySystems/ChemistrySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ChemistrySystem.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// This interface gives components behavior on whether entities solution (implying SolutionComponent is in place) is changed diff --git a/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs index fa7fdbaf4b..1babbc6ee6 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs @@ -9,7 +9,7 @@ using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Utility; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.GameObjects.EntitySystems.Click { public interface IExamine { @@ -62,7 +62,7 @@ namespace Content.Server.GameObjects.EntitySystems var inDetailsRange = Get() .InRangeUnobstructed(examiner.Transform.MapPosition, entity.Transform.MapPosition, - ExamineDetailsRange, predicate: entity0 => entity0 == examiner || entity0 == entity, insideBlockerValid: true); + ExamineDetailsRange, predicate: entity0 => entity0 == examiner || entity0 == entity, ignoreInsideBlocker: true); //Add component statuses from components that report one foreach (var examineComponent in entity.GetAllComponents()) diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index c92df5fcc5..15ec860880 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -3,8 +3,10 @@ using System.Linq; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Timing; using Content.Server.Interfaces.GameObjects; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Utility; using Content.Shared.GameObjects.Components.Inventory; +using Content.Shared.GameObjects.EntitySystemMessages; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Input; using JetBrains.Annotations; @@ -18,294 +20,14 @@ using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Map; -using Robust.Shared.Interfaces.Physics; using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Players; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.GameObjects.EntitySystems.Click { - /// - /// This interface gives components behavior when being clicked on by a user with an object in their hand - /// who is in range and has unobstructed reach of the target entity (allows inside blockers). - /// - public interface IInteractUsing - { - /// - /// Called when using one object on another when user is in range of the target entity. - /// - bool InteractUsing(InteractUsingEventArgs eventArgs); - } - - public class InteractUsingEventArgs : EventArgs, ITargetedInteractEventArgs - { - public IEntity User { get; set; } - public GridCoordinates ClickLocation { get; set; } - public IEntity Using { get; set; } - public IEntity Target { get; set; } - } - - public interface ITargetedInteractEventArgs - { - /// - /// Performer of the attack - /// - IEntity User { get; } - /// - /// Target of the attack - /// - IEntity Target { get; } - - } - - /// - /// This interface gives components behavior when being clicked on by a user with an empty hand - /// who is in range and has unobstructed reach of the target entity (allows inside blockers). - /// - public interface IInteractHand - { - /// - /// Called when a player directly interacts with an empty hand when user is in range of the target entity. - /// - bool InteractHand(InteractHandEventArgs eventArgs); - } - - public class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs - { - public IEntity User { get; set; } - public IEntity Target { get; set; } - } - - /// - /// This interface gives components behavior when being clicked on by a user with an object - /// outside the range of direct use - /// - public interface IRangedInteract - { - /// - /// Called when we try to interact with an entity out of range - /// - /// - bool RangedInteract(RangedInteractEventArgs eventArgs); - } - - [PublicAPI] - public class RangedInteractEventArgs : EventArgs - { - public IEntity User { get; set; } - public IEntity Using { get; set; } - public GridCoordinates ClickLocation { get; set; } - } - - /// - /// This interface gives components a behavior when clicking on another object and no interaction occurs, - /// at any range. - /// - public interface IAfterInteract - { - /// - /// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior - /// - void AfterInteract(AfterInteractEventArgs eventArgs); - } - - public class AfterInteractEventArgs : EventArgs - { - public IEntity User { get; set; } - public GridCoordinates ClickLocation { get; set; } - public IEntity Target { get; set; } - } - - /// - /// This interface gives components behavior when using the entity in your hands - /// - public interface IUse - { - /// - /// Called when we activate an object we are holding to use it - /// - /// - bool UseEntity(UseEntityEventArgs eventArgs); - } - - public class UseEntityEventArgs : EventArgs - { - public IEntity User { get; set; } - } - - /// - /// This interface gives components behavior when being activated in the world when the user - /// is in range and has unobstructed access to the target entity (allows inside blockers). - /// - public interface IActivate - { - /// - /// Called when this component is activated by another entity who is in range. - /// - void Activate(ActivateEventArgs eventArgs); - } - - public class ActivateEventArgs : EventArgs, ITargetedInteractEventArgs - { - public IEntity User { get; set; } - public IEntity Target { get; set; } - } - - /// - /// This interface gives components behavior when thrown. - /// - public interface IThrown - { - void Thrown(ThrownEventArgs eventArgs); - } - - public class ThrownEventArgs : EventArgs - { - public ThrownEventArgs(IEntity user) - { - User = user; - } - - public IEntity User { get; } - } - - /// - /// This interface gives components behavior when landing after being thrown. - /// - public interface ILand - { - void Land(LandEventArgs eventArgs); - } - - public class LandEventArgs : EventArgs - { - public LandEventArgs(IEntity user, GridCoordinates landingLocation) - { - User = user; - LandingLocation = landingLocation; - } - - public IEntity User { get; } - public GridCoordinates LandingLocation { get; } - } - - /// - /// This interface gives components behavior when their owner is put in an inventory slot. - /// - public interface IEquipped - { - void Equipped(EquippedEventArgs eventArgs); - } - - public class EquippedEventArgs : EventArgs - { - public EquippedEventArgs(IEntity user, EquipmentSlotDefines.Slots slot) - { - User = user; - Slot = slot; - } - - public IEntity User { get; } - public EquipmentSlotDefines.Slots Slot { get; } - } - - /// - /// This interface gives components behavior when their owner is removed from an inventory slot. - /// - public interface IUnequipped - { - void Unequipped(UnequippedEventArgs eventArgs); - } - - public class UnequippedEventArgs : EventArgs - { - public UnequippedEventArgs(IEntity user, EquipmentSlotDefines.Slots slot) - { - User = user; - Slot = slot; - } - - public IEntity User { get; } - public EquipmentSlotDefines.Slots Slot { get; } - } - - /// - /// This interface gives components behavior when being used to "attack". - /// - public interface IAttack - { - void Attack(AttackEventArgs eventArgs); - } - - public class AttackEventArgs : EventArgs - { - public AttackEventArgs(IEntity user, GridCoordinates clickLocation) - { - User = user; - ClickLocation = clickLocation; - } - - public IEntity User { get; } - public GridCoordinates ClickLocation { get; } - } - - /// - /// This interface gives components behavior when they're held on the selected hand. - /// - public interface IHandSelected - { - void HandSelected(HandSelectedEventArgs eventArgs); - } - - public class HandSelectedEventArgs : EventArgs - { - public HandSelectedEventArgs(IEntity user) - { - User = user; - } - - public IEntity User { get; } - } - - /// - /// This interface gives components behavior when they're held on a deselected hand. - /// - public interface IHandDeselected - { - void HandDeselected(HandDeselectedEventArgs eventArgs); - } - - public class HandDeselectedEventArgs : EventArgs - { - public HandDeselectedEventArgs(IEntity user) - { - User = user; - } - - public IEntity User { get; } - } - - /// - /// This interface gives components behavior when they're dropped by a mob. - /// - public interface IDropped - { - void Dropped(DroppedEventArgs eventArgs); - } - - public class DroppedEventArgs : EventArgs - { - public DroppedEventArgs(IEntity user) - { - User = user; - } - - public IEntity User { get; } - } - /// /// Governs interactions during clicking on entities /// @@ -318,6 +40,8 @@ namespace Content.Server.GameObjects.EntitySystems public override void Initialize() { + SubscribeNetworkEvent(HandleDragDropMessage); + CommandBinds.Builder .Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(HandleClientUseItemInHand)) @@ -334,6 +58,30 @@ namespace Content.Server.GameObjects.EntitySystems base.Shutdown(); } + private void HandleDragDropMessage(DragDropMessage msg, EntitySessionEventArgs args) + { + var performer = args.SenderSession.AttachedEntity; + if (!EntityManager.TryGetEntity(msg.Dropped, out var dropped)) return; + if (!EntityManager.TryGetEntity(msg.Target, out var target)) return; + + var interactionArgs = new DragDropEventArgs(performer, msg.DropLocation, dropped, target); + + // must be in range of both the target and the object they are drag / dropping + if (!InteractionChecks.InRangeUnobstructed(interactionArgs)) return; + + // trigger dragdrops on the dropped entity + foreach (var dragDrop in dropped.GetAllComponents()) + { + if (dragDrop.DragDrop(interactionArgs)) return; + } + + // trigger dragdropons on the targeted entity + foreach (var dragDropOn in target.GetAllComponents()) + { + if (dragDropOn.DragDropOn(interactionArgs)) return; + } + } + private bool HandleActivateItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid) { if (!EntityManager.TryGetEntity(uid, out var used)) @@ -572,7 +320,7 @@ namespace Content.Server.GameObjects.EntitySystems /// private void InteractAfter(IEntity user, IEntity weapon, GridCoordinates clickLocation) { - var message = new AfterAttackMessage(user, weapon, null, clickLocation); + var message = new AfterInteractMessage(user, weapon, null, clickLocation); RaiseLocalEvent(message); if (message.Handled) { @@ -594,7 +342,7 @@ namespace Content.Server.GameObjects.EntitySystems /// public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation) { - var attackMsg = new AttackByMessage(user, weapon, attacked, clickLocation); + var attackMsg = new InteractUsingMessage(user, weapon, attacked, clickLocation); RaiseLocalEvent(attackMsg); if (attackMsg.Handled) { @@ -620,7 +368,7 @@ namespace Content.Server.GameObjects.EntitySystems } } - var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation); + var afterAtkMsg = new AfterInteractMessage(user, weapon, attacked, clickLocation); RaiseLocalEvent(afterAtkMsg); if (afterAtkMsg.Handled) { @@ -906,7 +654,7 @@ namespace Content.Server.GameObjects.EntitySystems /// public void RangedInteraction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation) { - var rangedMsg = new RangedAttackMessage(user, weapon, attacked, clickLocation); + var rangedMsg = new RangedInteractMessage(user, weapon, attacked, clickLocation); RaiseLocalEvent(rangedMsg); if (rangedMsg.Handled) return; @@ -927,7 +675,7 @@ namespace Content.Server.GameObjects.EntitySystems } } - var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation); + var afterAtkMsg = new AfterInteractMessage(user, weapon, attacked, clickLocation); RaiseLocalEvent(afterAtkMsg); if (afterAtkMsg.Handled) return; @@ -988,422 +736,4 @@ namespace Content.Server.GameObjects.EntitySystems } } } - - /// - /// Raised when being clicked on or "attacked" by a user with an object in their hand - /// - [PublicAPI] - public class AttackByMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that triggered the attack. - /// - public IEntity User { get; } - - /// - /// Entity that the User attacked with. - /// - public IEntity ItemInHand { get; } - - /// - /// Entity that was attacked. - /// - public IEntity Attacked { get; } - - /// - /// The original location that was clicked by the user. - /// - public GridCoordinates ClickLocation { get; } - - public AttackByMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) - { - User = user; - ItemInHand = itemInHand; - Attacked = attacked; - ClickLocation = clickLocation; - } - } - - /// - /// Raised when being clicked on or "attacked" by a user with an empty hand. - /// - [PublicAPI] - public class AttackHandMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that triggered the attack. - /// - public IEntity User { get; } - - /// - /// Entity that was attacked. - /// - public IEntity Attacked { get; } - - public AttackHandMessage(IEntity user, IEntity attacked) - { - User = user; - Attacked = attacked; - } - } - - /// - /// Raised when being clicked by objects outside the range of direct use. - /// - [PublicAPI] - public class RangedAttackMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that triggered the attack. - /// - public IEntity User { get; } - - /// - /// Entity that the User attacked with. - /// - public IEntity ItemInHand { get; set; } - - /// - /// Entity that was attacked. - /// - public IEntity Attacked { get; } - - /// - /// Location that the user clicked outside of their interaction range. - /// - public GridCoordinates ClickLocation { get; } - - public RangedAttackMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) - { - User = user; - ItemInHand = itemInHand; - ClickLocation = clickLocation; - Attacked = attacked; - } - } - - /// - /// Raised when clicking on another object and no attack event was handled. - /// - [PublicAPI] - public class AfterAttackMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that triggered the attack. - /// - public IEntity User { get; } - - /// - /// Entity that the User attacked with. - /// - public IEntity ItemInHand { get; set; } - - /// - /// Entity that was attacked. This can be null if the attack did not click on an entity. - /// - public IEntity Attacked { get; } - - /// - /// Location that the user clicked outside of their interaction range. - /// - public GridCoordinates ClickLocation { get; } - - public AfterAttackMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) - { - User = user; - Attacked = attacked; - ClickLocation = clickLocation; - ItemInHand = itemInHand; - } - } - - /// - /// Raised when using the entity in your hands. - /// - [PublicAPI] - public class UseInHandMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity holding the item in their hand. - /// - public IEntity User { get; } - - /// - /// Item that was used. - /// - public IEntity Used { get; } - - public UseInHandMessage(IEntity user, IEntity used) - { - User = user; - Used = used; - } - } - - /// - /// Raised when throwing the entity in your hands. - /// - [PublicAPI] - public class ThrownMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that threw the item. - /// - public IEntity User { get; } - - /// - /// Item that was thrown. - /// - public IEntity Thrown { get; } - - public ThrownMessage(IEntity user, IEntity thrown) - { - User = user; - Thrown = thrown; - } - } - - /// - /// Raised when an entity that was thrown lands. - /// - [PublicAPI] - public class LandMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that threw the item. - /// - public IEntity User { get; } - - /// - /// Item that was thrown. - /// - public IEntity Thrown { get; } - - /// - /// Location where the item landed. - /// - public GridCoordinates LandLocation { get; } - - public LandMessage(IEntity user, IEntity thrown, GridCoordinates landLocation) - { - User = user; - Thrown = thrown; - LandLocation = landLocation; - } - } - - /// - /// Raised when equipping the entity in an inventory slot. - /// - [PublicAPI] - public class EquippedMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that equipped the item. - /// - public IEntity User { get; } - - /// - /// Item that was equipped. - /// - public IEntity Equipped { get; } - - /// - /// Slot where the item was placed. - /// - public EquipmentSlotDefines.Slots Slot { get; } - - public EquippedMessage(IEntity user, IEntity equipped, EquipmentSlotDefines.Slots slot) - { - User = user; - Equipped = equipped; - Slot = slot; - } - } - - /// - /// Raised when removing the entity from an inventory slot. - /// - [PublicAPI] - public class UnequippedMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that equipped the item. - /// - public IEntity User { get; } - - /// - /// Item that was equipped. - /// - public IEntity Equipped { get; } - - /// - /// Slot where the item was removed from. - /// - public EquipmentSlotDefines.Slots Slot { get; } - - public UnequippedMessage(IEntity user, IEntity equipped, EquipmentSlotDefines.Slots slot) - { - User = user; - Equipped = equipped; - Slot = slot; - } - } - - /// - /// Raised when an entity that was thrown lands. - /// - [PublicAPI] - public class DroppedMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that dropped the item. - /// - public IEntity User { get; } - - /// - /// Item that was dropped. - /// - public IEntity Dropped { get; } - - public DroppedMessage(IEntity user, IEntity dropped) - { - User = user; - Dropped = dropped; - } - } - - /// - /// Raised when an entity item in a hand is selected. - /// - [PublicAPI] - public class HandSelectedMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that owns the selected hand. - /// - public IEntity User { get; } - - /// - /// The item in question. - /// - public IEntity Item { get; } - - public HandSelectedMessage(IEntity user, IEntity item) - { - User = user; - Item = item; - } - } - - /// - /// Raised when an entity item in a hand is deselected. - /// - [PublicAPI] - public class HandDeselectedMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that owns the deselected hand. - /// - public IEntity User { get; } - - /// - /// The item in question. - /// - public IEntity Item { get; } - - public HandDeselectedMessage(IEntity user, IEntity item) - { - User = user; - Item = item; - } - } - - /// - /// Raised when an entity is activated in the world. - /// - [PublicAPI] - public class ActivateInWorldMessage : EntitySystemMessage - { - /// - /// If this message has already been "handled" by a previous system. - /// - public bool Handled { get; set; } - - /// - /// Entity that activated the world entity. - /// - public IEntity User { get; } - - /// - /// Entity that was activated in the world. - /// - public IEntity Activated { get; } - - public ActivateInWorldMessage(IEntity user, IEntity activated) - { - User = user; - Activated = activated; - } - } } diff --git a/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs b/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs index 926dbc15a2..f8fd65915e 100644 --- a/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs @@ -11,7 +11,7 @@ using Robust.Shared.Log; using Robust.Shared.Players; using Robust.Shared.Random; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] public sealed class CombatModeSystem : SharedCombatModeSystem diff --git a/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs b/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs index 2c5e40c328..d109b09588 100644 --- a/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs @@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Construction; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Stack; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces; using Content.Server.Utility; using Content.Shared.Construction; @@ -53,7 +54,7 @@ namespace Content.Server.GameObjects.EntitySystems SubscribeNetworkEvent(HandleStartStructureConstruction); SubscribeNetworkEvent(HandleStartItemConstruction); - SubscribeLocalEvent(HandleToolInteraction); + SubscribeLocalEvent(HandleToolInteraction); } private void HandleStartStructureConstruction(TryStartStructureConstructionMessage msg, EntitySessionEventArgs args) @@ -72,7 +73,7 @@ namespace Content.Server.GameObjects.EntitySystems TryStartItemConstruction(placingEnt, msg.PrototypeName); } - private void HandleToolInteraction(AfterAttackMessage msg) + private void HandleToolInteraction(AfterInteractMessage msg) { if(msg.Handled) return; @@ -239,7 +240,7 @@ namespace Content.Server.GameObjects.EntitySystems var prototype = _prototypeManager.Index(prototypeName); if (!InteractionChecks.InRangeUnobstructed(placingEnt, loc.ToMap(_mapManager), - ignoredEnt: placingEnt, insideBlockerValid: prototype.CanBuildInImpassable)) + ignoredEnt: placingEnt, ignoreInsideBlocker: prototype.CanBuildInImpassable)) { return false; } @@ -437,7 +438,7 @@ namespace Content.Server.GameObjects.EntitySystems { return false; } - + var sound = EntitySystemManager.GetEntitySystem(); switch (step) diff --git a/Content.Server/GameObjects/EntitySystems/DoorSystem.cs b/Content.Server/GameObjects/EntitySystems/DoorSystem.cs index 4455f8b3a7..fbe47ad5cc 100644 --- a/Content.Server/GameObjects/EntitySystems/DoorSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/DoorSystem.cs @@ -1,7 +1,8 @@ -using Robust.Shared.GameObjects; +using Content.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { class DoorSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/GravitySystem.cs b/Content.Server/GameObjects/EntitySystems/GravitySystem.cs index d257bcec53..27eb28a6c5 100644 --- a/Content.Server/GameObjects/EntitySystems/GravitySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GravitySystem.cs @@ -16,7 +16,7 @@ using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Random; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] public class GravitySystem: EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/HandHeldLightSystem.cs b/Content.Server/GameObjects/EntitySystems/HandHeldLightSystem.cs index a6df7eaae8..8dd40458c3 100644 --- a/Content.Server/GameObjects/EntitySystems/HandHeldLightSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HandHeldLightSystem.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Interactable; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class HandHeldLightSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs index bb549de99d..7e8455fc7c 100644 --- a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs @@ -20,8 +20,10 @@ using Robust.Shared.Players; using System; using Content.Server.GameObjects.Components.Items.Storage; using Content.Shared.GameObjects.EntitySystems; +using Content.Server.GameObjects; +using Content.Server.GameObjects.EntitySystems.Click; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] internal sealed class HandsSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/HungerSystem.cs b/Content.Server/GameObjects/EntitySystems/HungerSystem.cs index 671bc7f051..08d2c9bf98 100644 --- a/Content.Server/GameObjects/EntitySystems/HungerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HungerSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] public class HungerSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs index a64f1fec01..61e0b598a4 100644 --- a/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Instruments; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class InstrumentSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/LatheSystem.cs b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs index b85a251a4a..7c39ae0cc3 100644 --- a/Content.Server/GameObjects/EntitySystems/LatheSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Research; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class LatheSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs index 54c90381c0..8dc8379b0d 100644 --- a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Medical; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class MedicalScannerSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs b/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs index 82ba72537a..9dfd278add 100644 --- a/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs @@ -5,7 +5,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public sealed class MeleeWeaponSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs b/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs index 0e5c1f782d..8bb7d80bdd 100644 --- a/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs @@ -2,7 +2,7 @@ using Content.Server.GameObjects.Components.Kitchen; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class MicrowaveSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs index a98b8258f6..626e86a18e 100644 --- a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs @@ -1,5 +1,5 @@ -using Content.Server.GameObjects.Components; -using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects; +using Content.Server.GameObjects.Components; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.Components.Sound; @@ -80,7 +80,7 @@ namespace Content.Server.GameObjects.EntitySystems protected override void SetController(PhysicsComponent physics) { - ((PhysicsComponent) physics).SetController(); + physics.SetController(); } private static void PlayerAttached(PlayerAttachSystemMessage ev) @@ -97,6 +97,11 @@ namespace Content.Server.GameObjects.EntitySystems { ev.Entity.RemoveComponent(); } + + if (ev.Entity.TryGetComponent(out PhysicsComponent physics)) + { + (physics.Controller as MoverController)?.StopMoving(); + } } protected override void HandleFootsteps(IMoverComponent mover) diff --git a/Content.Server/GameObjects/EntitySystems/NodeGroupSystem.cs b/Content.Server/GameObjects/EntitySystems/NodeGroupSystem.cs new file mode 100644 index 0000000000..c1c719ad22 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/NodeGroupSystem.cs @@ -0,0 +1,19 @@ +using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.IoC; + +namespace Content.Server.GameObjects.EntitySystems +{ + public class NodeGroupSystem : EntitySystem + { +#pragma warning disable 649 + [Dependency] private readonly INodeGroupManager _groupManager; +#pragma warning restore 649 + + public override void Update(float frameTime) + { + base.Update(frameTime); + _groupManager.Update(frameTime); + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/PortalSystem.cs b/Content.Server/GameObjects/EntitySystems/PortalSystem.cs index 77eaf9bdcd..7ffc532422 100644 --- a/Content.Server/GameObjects/EntitySystems/PortalSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PortalSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] public class PortalSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs b/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs index 00e0ed20f1..cbaaaa981e 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using Robust.Shared.IoC; using Robust.Server.Interfaces.Timing; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public sealed class ApcSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs b/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs index db0068fec6..84f87f76b7 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs @@ -2,7 +2,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { internal class PowerSmesSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs index fc01bada12..604e475d9c 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs @@ -16,7 +16,7 @@ using CannyFastMath; using Math = CannyFastMath.Math; using MathF = CannyFastMath.MathF; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// Responsible for maintaining the solar-panel sun angle and updating coverage. diff --git a/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs b/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs index a1e4713aa5..6dd87f8b24 100644 --- a/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] internal sealed class ProjectileSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs b/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs index 4cb51c3f6e..77133b8462 100644 --- a/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs @@ -6,7 +6,7 @@ using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Map; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class PuddleSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/ResearchSystem.cs b/Content.Server/GameObjects/EntitySystems/ResearchSystem.cs index 6e4734139b..e67bd34895 100644 --- a/Content.Server/GameObjects/EntitySystems/ResearchSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ResearchSystem.cs @@ -4,7 +4,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class ResearchSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/RoundEndSystem.cs b/Content.Server/GameObjects/EntitySystems/RoundEndSystem.cs index 9077e94184..485ccb6b6f 100644 --- a/Content.Server/GameObjects/EntitySystems/RoundEndSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/RoundEndSystem.cs @@ -6,7 +6,7 @@ using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Timer = Robust.Shared.Timers.Timer; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class RoundEndSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/StomachSystem.cs b/Content.Server/GameObjects/EntitySystems/StomachSystem.cs index 9e7e12aac7..bbdc796c98 100644 --- a/Content.Server/GameObjects/EntitySystems/StomachSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StomachSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// Triggers digestion updates on diff --git a/Content.Server/GameObjects/EntitySystems/StorageSystem.cs b/Content.Server/GameObjects/EntitySystems/StorageSystem.cs index 29cff40f3d..867c7dc50c 100644 --- a/Content.Server/GameObjects/EntitySystems/StorageSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StorageSystem.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; -using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects; +using Content.Server.GameObjects.EntitySystems.Click; using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { class StorageSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/StunSystem.cs b/Content.Server/GameObjects/EntitySystems/StunSystem.cs index fea2a19502..ad5db08de4 100644 --- a/Content.Server/GameObjects/EntitySystems/StunSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StunSystem.cs @@ -4,7 +4,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class StunSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs b/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs index 76ddd151e3..a60c561bdf 100644 --- a/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/TemperatureSystem.cs @@ -1,7 +1,8 @@ -using Robust.Shared.GameObjects; +using Content.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { class TemperatureSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs b/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs index 1312b4e8ac..fa2b860f70 100644 --- a/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { [UsedImplicitly] public class ThirstSystem : EntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/TriggerSystem.cs b/Content.Server/GameObjects/EntitySystems/TriggerSystem.cs index 79b306c7d1..5a8bba0802 100644 --- a/Content.Server/GameObjects/EntitySystems/TriggerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/TriggerSystem.cs @@ -5,7 +5,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Timers; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// This interface gives components behavior when being "triggered" by timer or other conditions @@ -50,4 +50,4 @@ namespace Content.Server.GameObjects.EntitySystems }); } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs index 3a19749cc8..047a16c7c6 100644 --- a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs @@ -8,7 +8,7 @@ using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using static Content.Shared.GameObjects.EntitySystemMessages.VerbSystemMessages; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class VerbSystem : EntitySystem { diff --git a/Content.Server/GameObjects/EntitySystems/WelderSystem.cs b/Content.Server/GameObjects/EntitySystems/WelderSystem.cs index 411e3546fc..e35cb6144a 100644 --- a/Content.Server/GameObjects/EntitySystems/WelderSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/WelderSystem.cs @@ -3,7 +3,7 @@ using System.Linq; using Content.Server.GameObjects.Components.Interactable; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { /// /// Despite the name, it's only really used for the welder logic in tools. Go figure. diff --git a/Content.Server/GameObjects/EntitySystems/WireHackingSystem.cs b/Content.Server/GameObjects/EntitySystems/WireHackingSystem.cs index f13ae1c0a4..a8da8aff92 100644 --- a/Content.Server/GameObjects/EntitySystems/WireHackingSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/WireHackingSystem.cs @@ -3,7 +3,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.ViewVariables; using static Content.Shared.GameObjects.Components.SharedWiresComponent; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.Interfaces.GameObjects.Components.Interaction { public class WireHackingSystem : EntitySystem { diff --git a/Content.Server/GameTicking/GamePreset.cs b/Content.Server/GameTicking/GamePreset.cs index 5b4fdadf2d..0f9642184a 100644 --- a/Content.Server/GameTicking/GamePreset.cs +++ b/Content.Server/GameTicking/GamePreset.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Robust.Server.Interfaces.Player; +using Content.Shared.Preferences; namespace Content.Server.GameTicking { @@ -11,5 +12,6 @@ namespace Content.Server.GameTicking public abstract bool Start(IReadOnlyList readyPlayers, bool force = false); public virtual string ModeTitle => "Sandbox"; public virtual string Description => "Secret!"; + public Dictionary readyProfiles; } } diff --git a/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs b/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs index b59e7d7ae5..17def7d31a 100644 --- a/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs +++ b/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs @@ -1,17 +1,23 @@ -using System; -using System.Collections.Generic; -using Content.Server.GameTicking.GameRules; +using Content.Server.GameTicking.GameRules; +using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameTicking; using Content.Server.Mobs.Roles; using Content.Server.Players; -using Content.Server.Sandbox; -using NFluidsynth; +using Content.Shared.Antags; using Robust.Server.Interfaces.Player; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; +using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Logger = Robust.Shared.Log.Logger; +using System; +using System.Collections.Generic; +using System.Linq; +using Robust.Shared.Log; +using System.Threading.Tasks; +using Content.Shared.Preferences; + + namespace Content.Server.GameTicking.GamePresets { @@ -21,11 +27,14 @@ namespace Content.Server.GameTicking.GamePresets [Dependency] private readonly IChatManager _chatManager; [Dependency] private readonly IGameTicker _gameTicker; [Dependency] private readonly IRobustRandom _random; + [Dependency] private IPrototypeManager _prototypeManager; #pragma warning restore 649 public int MinPlayers { get; set; } = 5; public int MinTraitors { get; set; } = 2; public int PlayersPerTraitor { get; set; } = 5; + private static string TraitorID = "SuspicionTraitor"; + private static string InnocentID = "SuspicionInnocent"; public override bool Start(IReadOnlyList readyPlayers, bool force = false) { @@ -36,20 +45,48 @@ namespace Content.Server.GameTicking.GamePresets } var list = new List(readyPlayers); + var prefList = new List(); + + foreach (var player in list) + { + if (!readyProfiles.ContainsKey(player.Name)) + { + continue; + } + var profile = readyProfiles[player.Name]; + if (profile.AntagPreferences.Contains(_prototypeManager.Index(TraitorID).Name)) + { + prefList.Add(player); + } + } + var numTraitors = Math.Clamp(readyPlayers.Count % PlayersPerTraitor, MinTraitors, readyPlayers.Count); for (var i = 0; i < numTraitors; i++) { - var traitor = _random.PickAndTake(list); + IPlayerSession traitor; + if(prefList.Count() == 0) + { + traitor = _random.PickAndTake(list); + Logger.InfoS("preset", "Insufficient preferred traitors, picking at random."); + } + else + { + traitor = _random.PickAndTake(prefList); + list.Remove(traitor); + Logger.InfoS("preset", "Selected a preferred traitor."); + } var mind = traitor.Data.ContentData().Mind; - mind.AddRole(new SuspicionTraitorRole(mind)); + var antagPrototype = _prototypeManager.Index(TraitorID); + mind.AddRole(new SuspicionTraitorRole(mind, antagPrototype)); } foreach (var player in list) { var mind = player.Data.ContentData().Mind; - mind.AddRole(new SuspicionInnocentRole(mind)); + var antagPrototype = _prototypeManager.Index(InnocentID); + mind.AddRole(new SuspicionInnocentRole(mind, antagPrototype)); } _gameTicker.AddGameRule(); diff --git a/Content.Server/GameTicking/GameRules/RuleSuspicion.cs b/Content.Server/GameTicking/GameRules/RuleSuspicion.cs index 91b16f3aaf..50f236072d 100644 --- a/Content.Server/GameTicking/GameRules/RuleSuspicion.cs +++ b/Content.Server/GameTicking/GameRules/RuleSuspicion.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading; using Content.Server.GameObjects; using Content.Server.GameObjects.Components.Mobs; @@ -38,8 +39,6 @@ namespace Content.Server.GameTicking.GameRules public override void Added() { - _chatManager.DispatchServerAnnouncement("There are traitors on the station! Find them, and kill them!"); - _entityManager.EventBus.SubscribeEvent(EventSource.Local, this, _onMobDamageStateChanged); Timer.SpawnRepeating(DeadCheckDelay, _checkWinConditions, _checkTimerCancel.Token); @@ -86,7 +85,6 @@ namespace Content.Server.GameTicking.GameRules { continue; } - if (playerSession.ContentData().Mind.HasRole()) traitorsAlive++; else diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index c9b74a3cbd..f260aeaa34 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -10,6 +10,7 @@ using Content.Server.GameObjects.Components.Markers; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Observer; using Content.Server.GameObjects.Components.PDA; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding; using Content.Server.GameTicking.GamePresets; @@ -23,6 +24,7 @@ using Content.Shared; using Content.Shared.Chat; using Content.Shared.GameObjects.Components.PDA; using Content.Shared.Jobs; +using Content.Shared.Physics; using Content.Shared.Preferences; using Prometheus; using Robust.Server.Interfaces; @@ -33,6 +35,7 @@ using Robust.Server.ServerStatus; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.GameObjects; @@ -266,12 +269,12 @@ namespace Content.Server.GameTicking } // Time to start the preset. - var preset = MakeGamePreset(); + var preset = MakeGamePreset(profiles); if (!preset.Start(assignedJobs.Keys.ToList(), force)) { SetStartPreset(_configurationManager.GetCVar("game.fallbackpreset")); - var newPreset = MakeGamePreset(); + var newPreset = MakeGamePreset(profiles); _chatManager.DispatchServerAnnouncement( $"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}..."); if (!newPreset.Start(readyPlayers, force)) @@ -305,7 +308,7 @@ namespace Content.Server.GameTicking //Tell every client the round has ended. var roundEndMessage = _netManager.CreateNetMessage(); - roundEndMessage.GamemodeTitle = MakeGamePreset().ModeTitle; + roundEndMessage.GamemodeTitle = MakeGamePreset(null).ModeTitle; //Get the timespan of the round. roundEndMessage.RoundDuration = IoCManager.Resolve().RealTime.Subtract(_roundStartTimeSpan); @@ -317,13 +320,13 @@ namespace Content.Server.GameTicking var mind = ply.ContentData().Mind; if (mind != null) { - var antag = mind.AllRoles.Any(role => role.Antag); + var antag = mind.AllRoles.Any(role => role.Antagonist); var playerEndRoundInfo = new RoundEndPlayerInfo() { PlayerOOCName = ply.Name, PlayerICName = mind.CurrentEntity.Name, Role = antag - ? mind.AllRoles.First(role => role.Antag).Name + ? mind.AllRoles.First(role => role.Antagonist).Name : mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unknown"), Antag = antag }; @@ -804,7 +807,7 @@ namespace Content.Server.GameTicking var mindComponent = mob.GetComponent(); if (mindComponent.HasMind) //Redundancy checks. { - if (mindComponent.Mind.AllRoles.Any(role => role.Antag)) //Give antags a new uplinkaccount. + if (mindComponent.Mind.AllRoles.Any(role => role.Antagonist)) //Give antags a new uplinkaccount. { var uplinkAccount = new UplinkAccount(mob.Uid, @@ -882,8 +885,8 @@ namespace Content.Server.GameTicking private string GetInfoText() { - var gmTitle = MakeGamePreset().ModeTitle; - var desc = MakeGamePreset().Description; + var gmTitle = MakeGamePreset(null).ModeTitle; + var desc = MakeGamePreset(null).Description; return _localization.GetString(@"Hi and welcome to [color=white]Space Station 14![/color] The current game mode is: [color=white]{0}[/color]. @@ -897,9 +900,11 @@ The current game mode is: [color=white]{0}[/color]. _netManager.ServerSendToMany(infoMsg, _playersInLobby.Keys.Select(p => p.ConnectedClient).ToList()); } - private GamePreset MakeGamePreset() + private GamePreset MakeGamePreset(Dictionary readyProfiles) { - return _dynamicTypeFactory.CreateInstance(_presetType ?? typeof(PresetSandbox)); + var preset = _dynamicTypeFactory.CreateInstance(_presetType ?? typeof(PresetSandbox)); + preset.readyProfiles = readyProfiles; + return preset; } #pragma warning disable 649 diff --git a/Content.Server/Health/BodySystem/BodyManagerComponent.cs b/Content.Server/Health/BodySystem/BodyManagerComponent.cs index 0c491f02e4..c7e299b1f8 100644 --- a/Content.Server/Health/BodySystem/BodyManagerComponent.cs +++ b/Content.Server/Health/BodySystem/BodyManagerComponent.cs @@ -9,7 +9,7 @@ using Robust.Shared.ViewVariables; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; using System.Linq; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; namespace Content.Server.BodySystem { diff --git a/Content.Server/Health/BodySystem/BodyPart/DroppedBodyPartComponent.cs b/Content.Server/Health/BodySystem/BodyPart/DroppedBodyPartComponent.cs index cb83dfea3f..ffad52bc07 100644 --- a/Content.Server/Health/BodySystem/BodyPart/DroppedBodyPartComponent.cs +++ b/Content.Server/Health/BodySystem/BodyPart/DroppedBodyPartComponent.cs @@ -15,6 +15,7 @@ using Robust.Server.Interfaces.Player; using Content.Shared.Interfaces; using Robust.Shared.Interfaces.Random; using System.Linq; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.Localization; namespace Content.Server.BodySystem @@ -22,7 +23,7 @@ namespace Content.Server.BodySystem /// /// Component representing a dropped, tangible entity. - /// + /// [RegisterComponent] public class DroppedBodyPartComponent : Component, IAfterInteract, IBodyPartContainer { diff --git a/Content.Server/Health/BodySystem/BodyScanner/BodyScannerComponent.cs b/Content.Server/Health/BodySystem/BodyScanner/BodyScannerComponent.cs index f28f683e9b..4fe2a5f309 100644 --- a/Content.Server/Health/BodySystem/BodyScanner/BodyScannerComponent.cs +++ b/Content.Server/Health/BodySystem/BodyScanner/BodyScannerComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/Health/BodySystem/Mechanism/DroppedMechanismComponent.cs b/Content.Server/Health/BodySystem/Mechanism/DroppedMechanismComponent.cs index cf93a592a0..32c788d233 100644 --- a/Content.Server/Health/BodySystem/Mechanism/DroppedMechanismComponent.cs +++ b/Content.Server/Health/BodySystem/Mechanism/DroppedMechanismComponent.cs @@ -16,13 +16,14 @@ using Robust.Server.Interfaces.Player; using Robust.Shared.Interfaces.Random; using Robust.Shared.Interfaces.GameObjects; using System.Diagnostics; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.Localization; namespace Content.Server.BodySystem { /// /// Component representing a dropped, tangible entity. - /// + /// [RegisterComponent] public class DroppedMechanismComponent : Component, IAfterInteract { @@ -130,7 +131,7 @@ namespace Content.Server.BodySystem { } /// - /// Called after the client chooses from a list of possible BodyParts that can be operated on. + /// Called after the client chooses from a list of possible BodyParts that can be operated on. /// private void HandleReceiveBodyPart(int key) { diff --git a/Content.Server/Health/BodySystem/Surgery/Surgeon/SurgeryToolComponent.cs b/Content.Server/Health/BodySystem/Surgery/Surgeon/SurgeryToolComponent.cs index 457a9fb55c..d908a053fe 100644 --- a/Content.Server/Health/BodySystem/Surgery/Surgeon/SurgeryToolComponent.cs +++ b/Content.Server/Health/BodySystem/Surgery/Surgeon/SurgeryToolComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.BodySystem; using Content.Shared.GameObjects; using Content.Shared.Interfaces; @@ -65,7 +66,7 @@ namespace Content.Server.BodySystem { var toSend = new Dictionary(); //Create dictionary to send to client (text to be shown : data sent back if selected) foreach (var(key, value) in bodyManager.PartDictionary) { //For each limb in the target, add it to our cache if it is a valid option. - if (value.SurgeryCheck(_surgeryType)) + if (value.SurgeryCheck(_surgeryType)) { _optionsCache.Add(_idHash, value); toSend.Add(key + ": " + value.Name, _idHash++); @@ -171,7 +172,7 @@ namespace Content.Server.BodySystem } /// - /// Called after the client chooses from a list of possible BodyParts that can be operated on. + /// Called after the client chooses from a list of possible BodyParts that can be operated on. /// private void HandleReceiveBodyPart(int key) { diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IActivate.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IActivate.cs new file mode 100644 index 0000000000..13e8c171ab --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IActivate.cs @@ -0,0 +1,53 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when being activated in the world when the user + /// is in range and has unobstructed access to the target entity (allows inside blockers). + /// + public interface IActivate + { + /// + /// Called when this component is activated by another entity who is in range. + /// + void Activate(ActivateEventArgs eventArgs); + } + + public class ActivateEventArgs : EventArgs, ITargetedInteractEventArgs + { + public IEntity User { get; set; } + public IEntity Target { get; set; } + } + + /// + /// Raised when an entity is activated in the world. + /// + [PublicAPI] + public class ActivateInWorldMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that activated the world entity. + /// + public IEntity User { get; } + + /// + /// Entity that was activated in the world. + /// + public IEntity Activated { get; } + + public ActivateInWorldMessage(IEntity user, IEntity activated) + { + User = user; + Activated = activated; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs new file mode 100644 index 0000000000..ed0a167850 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs @@ -0,0 +1,68 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components a behavior when clicking on another object and no interaction occurs, + /// at any range. + /// + public interface IAfterInteract + { + /// + /// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior + /// + void AfterInteract(AfterInteractEventArgs eventArgs); + } + + public class AfterInteractEventArgs : EventArgs + { + public IEntity User { get; set; } + public GridCoordinates ClickLocation { get; set; } + public IEntity Target { get; set; } + } + + /// + /// Raised when clicking on another object and no attack event was handled. + /// + [PublicAPI] + public class AfterInteractMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that triggered the attack. + /// + public IEntity User { get; } + + /// + /// Entity that the User attacked with. + /// + public IEntity ItemInHand { get; set; } + + /// + /// Entity that was attacked. This can be null if the attack did not click on an entity. + /// + public IEntity Attacked { get; } + + /// + /// Location that the user clicked outside of their interaction range. + /// + public GridCoordinates ClickLocation { get; } + + public AfterInteractMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) + { + User = user; + Attacked = attacked; + ClickLocation = clickLocation; + ItemInHand = itemInHand; + } + } + +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IAttack.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IAttack.cs new file mode 100644 index 0000000000..1df2790bcb --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IAttack.cs @@ -0,0 +1,26 @@ +using System; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when being used to "attack". + /// + public interface IAttack + { + void Attack(AttackEventArgs eventArgs); + } + + public class AttackEventArgs : EventArgs + { + public AttackEventArgs(IEntity user, GridCoordinates clickLocation) + { + User = user; + ClickLocation = clickLocation; + } + + public IEntity User { get; } + public GridCoordinates ClickLocation { get; } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDrop.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDrop.cs new file mode 100644 index 0000000000..b9d47eef12 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDrop.cs @@ -0,0 +1,40 @@ +using System; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface allows the component's entity to be dragged and dropped by mouse onto another entity and gives it + /// behavior when that occurs. + /// + public interface IDragDrop + { + /// + /// Invoked server-side when this component's entity is being dragged and dropped on another. + /// + /// There is no other server-side drag and drop check other than a range check, so make sure to validate + /// if this object can be dropped on the target object! + /// + /// true iff an interaction occurred and no further interaction should + /// be processed for this drop. + bool DragDrop(DragDropEventArgs eventArgs); + } + + public class DragDropEventArgs : EventArgs + { + public DragDropEventArgs(IEntity user, GridCoordinates dropLocation, IEntity dropped, IEntity target) + { + User = user; + DropLocation = dropLocation; + Dropped = dropped; + Target = target; + } + + public IEntity User { get; } + public GridCoordinates DropLocation { get; } + public IEntity Dropped { get; } + public IEntity Target { get; } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDropOn.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDropOn.cs new file mode 100644 index 0000000000..00ac843dda --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDragDropOn.cs @@ -0,0 +1,24 @@ +using System; +using Content.Server.Interfaces.GameObjects.Components.Interaction; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface allows the component's entity to be dragged and dropped onto by another entity and gives it + /// behavior when that occurs. + /// + public interface IDragDropOn + { + /// + /// Invoked server-side when another entity is being dragged and dropped onto this one + /// + /// There is no other server-side drag and drop check other than a range check, so make sure to validate + /// if this object can be dropped on the dropped object! + /// + /// true iff an interaction occurred and no further interaction should + /// be processed for this drop. + bool DragDropOn(DragDropEventArgs eventArgs); + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IDropped.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDropped.cs new file mode 100644 index 0000000000..a28c31dfe8 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IDropped.cs @@ -0,0 +1,53 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when they're dropped by a mob. + /// + public interface IDropped + { + void Dropped(DroppedEventArgs eventArgs); + } + + public class DroppedEventArgs : EventArgs + { + public DroppedEventArgs(IEntity user) + { + User = user; + } + + public IEntity User { get; } + } + + /// + /// Raised when an entity is dropped + /// + [PublicAPI] + public class DroppedMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that dropped the item. + /// + public IEntity User { get; } + + /// + /// Item that was dropped. + /// + public IEntity Dropped { get; } + + public DroppedMessage(IEntity user, IEntity dropped) + { + User = user; + Dropped = dropped; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IEquipped.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IEquipped.cs new file mode 100644 index 0000000000..ce99fed577 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IEquipped.cs @@ -0,0 +1,62 @@ +using System; +using Content.Shared.GameObjects.Components.Inventory; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when their owner is put in an inventory slot. + /// + public interface IEquipped + { + void Equipped(EquippedEventArgs eventArgs); + } + + public class EquippedEventArgs : EventArgs + { + public EquippedEventArgs(IEntity user, EquipmentSlotDefines.Slots slot) + { + User = user; + Slot = slot; + } + + public IEntity User { get; } + public EquipmentSlotDefines.Slots Slot { get; } + } + + /// + /// Raised when equipping the entity in an inventory slot. + /// + [PublicAPI] + public class EquippedMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that equipped the item. + /// + public IEntity User { get; } + + /// + /// Item that was equipped. + /// + public IEntity Equipped { get; } + + /// + /// Slot where the item was placed. + /// + public EquipmentSlotDefines.Slots Slot { get; } + + public EquippedMessage(IEntity user, IEntity equipped, EquipmentSlotDefines.Slots slot) + { + User = user; + Equipped = equipped; + Slot = slot; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandDeselected.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandDeselected.cs new file mode 100644 index 0000000000..a6e481613d --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandDeselected.cs @@ -0,0 +1,53 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when they're held on a deselected hand. + /// + public interface IHandDeselected + { + void HandDeselected(HandDeselectedEventArgs eventArgs); + } + + public class HandDeselectedEventArgs : EventArgs + { + public HandDeselectedEventArgs(IEntity user) + { + User = user; + } + + public IEntity User { get; } + } + + /// + /// Raised when an entity item in a hand is deselected. + /// + [PublicAPI] + public class HandDeselectedMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that owns the deselected hand. + /// + public IEntity User { get; } + + /// + /// The item in question. + /// + public IEntity Item { get; } + + public HandDeselectedMessage(IEntity user, IEntity item) + { + User = user; + Item = item; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandSelected.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandSelected.cs new file mode 100644 index 0000000000..846ee64dd0 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IHandSelected.cs @@ -0,0 +1,53 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when they're held on the selected hand. + /// + public interface IHandSelected + { + void HandSelected(HandSelectedEventArgs eventArgs); + } + + public class HandSelectedEventArgs : EventArgs + { + public HandSelectedEventArgs(IEntity user) + { + User = user; + } + + public IEntity User { get; } + } + + /// + /// Raised when an entity item in a hand is selected. + /// + [PublicAPI] + public class HandSelectedMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that owns the selected hand. + /// + public IEntity User { get; } + + /// + /// The item in question. + /// + public IEntity Item { get; } + + public HandSelectedMessage(IEntity user, IEntity item) + { + User = user; + Item = item; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractHand.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractHand.cs new file mode 100644 index 0000000000..b4820980bd --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractHand.cs @@ -0,0 +1,54 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when being clicked on by a user with an empty hand + /// who is in range and has unobstructed reach of the target entity (allows inside blockers). + /// + public interface IInteractHand + { + /// + /// Called when a player directly interacts with an empty hand when user is in range of the target entity. + /// + bool InteractHand(InteractHandEventArgs eventArgs); + } + + public class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs + { + public IEntity User { get; set; } + public IEntity Target { get; set; } + } + + + /// + /// Raised when being clicked on or "attacked" by a user with an empty hand. + /// + [PublicAPI] + public class AttackHandMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that triggered the attack. + /// + public IEntity User { get; } + + /// + /// Entity that was attacked. + /// + public IEntity Attacked { get; } + + public AttackHandMessage(IEntity user, IEntity attacked) + { + User = user; + Attacked = attacked; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractUsing.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractUsing.cs new file mode 100644 index 0000000000..466b984fbf --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IInteractUsing.cs @@ -0,0 +1,68 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when being clicked on by a user with an object in their hand + /// who is in range and has unobstructed reach of the target entity (allows inside blockers). + /// + public interface IInteractUsing + { + /// + /// Called when using one object on another when user is in range of the target entity. + /// + bool InteractUsing(InteractUsingEventArgs eventArgs); + } + + public class InteractUsingEventArgs : EventArgs, ITargetedInteractEventArgs + { + public IEntity User { get; set; } + public GridCoordinates ClickLocation { get; set; } + public IEntity Using { get; set; } + public IEntity Target { get; set; } + } + + /// + /// Raised when being clicked on or "attacked" by a user with an object in their hand + /// + [PublicAPI] + public class InteractUsingMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that triggered the attack. + /// + public IEntity User { get; } + + /// + /// Entity that the User attacked with. + /// + public IEntity ItemInHand { get; } + + /// + /// Entity that was attacked. + /// + public IEntity Attacked { get; } + + /// + /// The original location that was clicked by the user. + /// + public GridCoordinates ClickLocation { get; } + + public InteractUsingMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) + { + User = user; + ItemInHand = itemInHand; + Attacked = attacked; + ClickLocation = clickLocation; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/ILand.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/ILand.cs new file mode 100644 index 0000000000..1915f5fc69 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/ILand.cs @@ -0,0 +1,62 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when landing after being thrown. + /// + public interface ILand + { + void Land(LandEventArgs eventArgs); + } + + public class LandEventArgs : EventArgs + { + public LandEventArgs(IEntity user, GridCoordinates landingLocation) + { + User = user; + LandingLocation = landingLocation; + } + + public IEntity User { get; } + public GridCoordinates LandingLocation { get; } + } + + /// + /// Raised when an entity that was thrown lands. + /// + [PublicAPI] + public class LandMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that threw the item. + /// + public IEntity User { get; } + + /// + /// Item that was thrown. + /// + public IEntity Thrown { get; } + + /// + /// Location where the item landed. + /// + public GridCoordinates LandLocation { get; } + + public LandMessage(IEntity user, IEntity thrown, GridCoordinates landLocation) + { + User = user; + Thrown = thrown; + LandLocation = landLocation; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IRangedInteract.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IRangedInteract.cs new file mode 100644 index 0000000000..d1f188cd4e --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IRangedInteract.cs @@ -0,0 +1,69 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when being clicked on by a user with an object + /// outside the range of direct use + /// + public interface IRangedInteract + { + /// + /// Called when we try to interact with an entity out of range + /// + /// + bool RangedInteract(RangedInteractEventArgs eventArgs); + } + + [PublicAPI] + public class RangedInteractEventArgs : EventArgs + { + public IEntity User { get; set; } + public IEntity Using { get; set; } + public GridCoordinates ClickLocation { get; set; } + } + + /// + /// Raised when being clicked by objects outside the range of direct use. + /// + [PublicAPI] + public class RangedInteractMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that triggered the attack. + /// + public IEntity User { get; } + + /// + /// Entity that the User attacked with. + /// + public IEntity ItemInHand { get; set; } + + /// + /// Entity that was attacked. + /// + public IEntity Attacked { get; } + + /// + /// Location that the user clicked outside of their interaction range. + /// + public GridCoordinates ClickLocation { get; } + + public RangedInteractMessage(IEntity user, IEntity itemInHand, IEntity attacked, GridCoordinates clickLocation) + { + User = user; + ItemInHand = itemInHand; + ClickLocation = clickLocation; + Attacked = attacked; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/ITargetedInteractEventArgs.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/ITargetedInteractEventArgs.cs new file mode 100644 index 0000000000..028e3d3643 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/ITargetedInteractEventArgs.cs @@ -0,0 +1,17 @@ +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + public interface ITargetedInteractEventArgs + { + /// + /// Performer of the attack + /// + IEntity User { get; } + /// + /// Target of the attack + /// + IEntity Target { get; } + + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IThrown.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IThrown.cs new file mode 100644 index 0000000000..ca3a798963 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IThrown.cs @@ -0,0 +1,53 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when thrown. + /// + public interface IThrown + { + void Thrown(ThrownEventArgs eventArgs); + } + + public class ThrownEventArgs : EventArgs + { + public ThrownEventArgs(IEntity user) + { + User = user; + } + + public IEntity User { get; } + } + + /// + /// Raised when throwing the entity in your hands. + /// + [PublicAPI] + public class ThrownMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that threw the item. + /// + public IEntity User { get; } + + /// + /// Item that was thrown. + /// + public IEntity Thrown { get; } + + public ThrownMessage(IEntity user, IEntity thrown) + { + User = user; + Thrown = thrown; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IUnequipped.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IUnequipped.cs new file mode 100644 index 0000000000..32f2efa087 --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IUnequipped.cs @@ -0,0 +1,64 @@ +using System; +using Content.Shared.GameObjects.Components.Inventory; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when their owner is removed from an inventory slot. + /// + public interface IUnequipped + { + void Unequipped(UnequippedEventArgs eventArgs); + } + + public class UnequippedEventArgs : EventArgs + { + public UnequippedEventArgs(IEntity user, EquipmentSlotDefines.Slots slot) + { + User = user; + Slot = slot; + } + + public IEntity User { get; } + public EquipmentSlotDefines.Slots Slot { get; } + } + + /// + /// Raised when removing the entity from an inventory slot. + /// + [PublicAPI] + public class UnequippedMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity that equipped the item. + /// + public IEntity User { get; } + + /// + /// Item that was equipped. + /// + public IEntity Equipped { get; } + + /// + /// Slot where the item was removed from. + /// + public EquipmentSlotDefines.Slots Slot { get; } + + public UnequippedMessage(IEntity user, IEntity equipped, EquipmentSlotDefines.Slots slot) + { + User = user; + Equipped = equipped; + Slot = slot; + } + } + + +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Interaction/IUse.cs b/Content.Server/Interfaces/GameObjects/Components/Interaction/IUse.cs new file mode 100644 index 0000000000..6da5926e6c --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interaction/IUse.cs @@ -0,0 +1,52 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects.Components.Interaction +{ + /// + /// This interface gives components behavior when using the entity in your hands + /// + public interface IUse + { + /// + /// Called when we activate an object we are holding to use it + /// + /// + bool UseEntity(UseEntityEventArgs eventArgs); + } + + public class UseEntityEventArgs : EventArgs + { + public IEntity User { get; set; } + } + + /// + /// Raised when using the entity in your hands. + /// + [PublicAPI] + public class UseInHandMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// Entity holding the item in their hand. + /// + public IEntity User { get; } + + /// + /// Item that was used. + /// + public IEntity Used { get; } + + public UseInHandMessage(IEntity user, IEntity used) + { + User = user; + Used = used; + } + } +} diff --git a/Content.Server/Mobs/Commands.cs b/Content.Server/Mobs/Commands.cs index 2b04692431..a31eac223c 100644 --- a/Content.Server/Mobs/Commands.cs +++ b/Content.Server/Mobs/Commands.cs @@ -1,4 +1,5 @@ using System.Text; +using Content.Server.GameObjects.Components.Mobs; using Content.Server.Mobs.Roles; using Content.Server.Players; using Content.Shared.Jobs; @@ -117,4 +118,52 @@ namespace Content.Server.Mobs } } } + + public class AddOverlayCommand : IClientCommand + { + public string Command => "addoverlay"; + public string Description => "Adds an overlay by its ID"; + public string Help => "addoverlay "; + + public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + { + if (args.Length != 1) + { + shell.SendText(player, "Expected 1 argument."); + return; + } + + if (player?.AttachedEntity != null) + { + if (player.AttachedEntity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) + { + overlayEffectsComponent.AddOverlay(args[0]); + } + } + } + } + + public class RemoveOverlayCommand : IClientCommand + { + public string Command => "rmoverlay"; + public string Description => "Removes an overlay by its ID"; + public string Help => "rmoverlay "; + + public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + { + if (args.Length != 1) + { + shell.SendText(player, "Expected 1 argument."); + return; + } + + if (player?.AttachedEntity != null) + { + if (player.AttachedEntity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) + { + overlayEffectsComponent.RemoveOverlay(args[0]); + } + } + } + } } diff --git a/Content.Server/Mobs/Mind.cs b/Content.Server/Mobs/Mind.cs index 5e631f68ec..17a453b0e5 100644 --- a/Content.Server/Mobs/Mind.cs +++ b/Content.Server/Mobs/Mind.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Players; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; diff --git a/Content.Server/Mobs/Role.cs b/Content.Server/Mobs/Role.cs index f78b579f11..c5dff2391f 100644 --- a/Content.Server/Mobs/Role.cs +++ b/Content.Server/Mobs/Role.cs @@ -1,7 +1,7 @@ // Hey look, // Antag Datums. -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Robust.Shared.Utility; namespace Content.Server.Mobs @@ -26,7 +26,7 @@ namespace Content.Server.Mobs /// /// Whether this role should be considered antagonistic or not. /// - public abstract bool Antag { get; } + public abstract bool Antagonist { get; } protected Role(Mind mind) { diff --git a/Content.Server/Mobs/Roles/Job.cs b/Content.Server/Mobs/Roles/Job.cs index 680a91ff20..33db5a65dc 100644 --- a/Content.Server/Mobs/Roles/Job.cs +++ b/Content.Server/Mobs/Roles/Job.cs @@ -11,7 +11,7 @@ namespace Content.Server.Mobs.Roles public JobPrototype Prototype { get; } public override string Name { get; } - public override bool Antag => false; + public override bool Antagonist => false; public string StartingGear => Prototype.StartingGear; diff --git a/Content.Server/Mobs/Roles/SuspicionInnocentRole.cs b/Content.Server/Mobs/Roles/SuspicionInnocentRole.cs index 177a8d3bbd..4c2f16f6a9 100644 --- a/Content.Server/Mobs/Roles/SuspicionInnocentRole.cs +++ b/Content.Server/Mobs/Roles/SuspicionInnocentRole.cs @@ -2,24 +2,32 @@ using Content.Server.GameObjects; using Content.Server.Interfaces.Chat; using Robust.Shared.IoC; using Robust.Shared.Utility; +using Content.Shared.Antags; namespace Content.Server.Mobs.Roles { public class SuspicionInnocentRole : Role { - public SuspicionInnocentRole(Mind mind) : base(mind) + public AntagPrototype Prototype { get; } + + public SuspicionInnocentRole(Mind mind, AntagPrototype antagPrototype) : base(mind) { + Prototype = antagPrototype; + Name = antagPrototype.Name; + Antagonist = antagPrototype.Antagonist; } - public override string Name => "Innocent"; - public override bool Antag => false; + public override string Name { get; } + public string Objective => Prototype.Objective; + public override bool Antagonist { get; } public override void Greet() { base.Greet(); var chat = IoCManager.Resolve(); - chat.DispatchServerMessage(Mind.Session, "You're an innocent!"); + chat.DispatchServerMessage(Mind.Session, $"You're a {Name}!"); + chat.DispatchServerMessage(Mind.Session, $"Objective: {Objective}"); } } } diff --git a/Content.Server/Mobs/Roles/SuspicionTraitorRole.cs b/Content.Server/Mobs/Roles/SuspicionTraitorRole.cs index 65c1e10306..5d19854454 100644 --- a/Content.Server/Mobs/Roles/SuspicionTraitorRole.cs +++ b/Content.Server/Mobs/Roles/SuspicionTraitorRole.cs @@ -1,25 +1,33 @@ -using Content.Server.GameObjects; +using Content.Server.GameObjects; using Content.Server.Interfaces.Chat; using Robust.Shared.IoC; using Robust.Shared.Utility; +using Content.Shared.Antags; namespace Content.Server.Mobs.Roles { public sealed class SuspicionTraitorRole : Role { - public SuspicionTraitorRole(Mind mind) : base(mind) + public AntagPrototype Prototype { get; } + + public SuspicionTraitorRole(Mind mind, AntagPrototype antagPrototype) : base(mind) { + Prototype = antagPrototype; + Name = antagPrototype.Name; + Antagonist = antagPrototype.Antagonist; } - public override string Name => "Traitor"; - public override bool Antag => true; + public override string Name { get; } + public string Objective => Prototype.Objective; + public override bool Antagonist { get; } public override void Greet() { base.Greet(); var chat = IoCManager.Resolve(); - chat.DispatchServerMessage(Mind.Session, "You're a traitor!"); + chat.DispatchServerMessage(Mind.Session, $"You're a {Name}!"); + chat.DispatchServerMessage(Mind.Session, $"Objective: {Objective}"); } } } diff --git a/Content.Server/Observer/Ghost.cs b/Content.Server/Observer/Ghost.cs index 31a1d42bd3..7924d9f704 100644 --- a/Content.Server/Observer/Ghost.cs +++ b/Content.Server/Observer/Ghost.cs @@ -1,6 +1,6 @@ using Content.Server.GameObjects; using Content.Server.GameObjects.Components.Observer; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameTicking; using Content.Server.Players; using Content.Shared.GameObjects; diff --git a/Content.Server/PDA/PDAUplinkManager.cs b/Content.Server/PDA/PDAUplinkManager.cs index 6deda8e891..f148d46e4b 100644 --- a/Content.Server/PDA/PDAUplinkManager.cs +++ b/Content.Server/PDA/PDAUplinkManager.cs @@ -57,7 +57,7 @@ namespace Content.Server.PDA var entity = _entityManager.GetEntity(acc.AccountHolder); if (entity.TryGetComponent(out MindComponent mindComponent)) { - if (mindComponent.Mind.AllRoles.Any(role => !role.Antag)) + if (mindComponent.Mind.AllRoles.Any(role => !role.Antagonist)) { return false; } diff --git a/Content.Server/Preferences/PreferencesDatabase.cs b/Content.Server/Preferences/PreferencesDatabase.cs index b29ff4a255..6c6c4719d0 100644 --- a/Content.Server/Preferences/PreferencesDatabase.cs +++ b/Content.Server/Preferences/PreferencesDatabase.cs @@ -107,6 +107,10 @@ namespace Content.Server.Preferences .Where(j => j.Value != JobPriority.Never) .Select(j => new Job {JobName = j.Key, Priority = (DbJobPriority) j.Value}) ); + entity.Antags.AddRange( + humanoid.AntagPreferences + .Select(a => new Antag {AntagName = a}) + ); await _prefsDb.SaveCharacterSlotAsync(username, entity); } finally @@ -140,6 +144,7 @@ namespace Content.Server.Preferences private static HumanoidCharacterProfile ConvertProfiles(HumanoidProfile profile) { var jobs = profile.Jobs.ToDictionary(j => j.JobName, j => (JobPriority) j.Priority); + var antags = profile.Antags.Select(a => a.AntagName); return new HumanoidCharacterProfile( profile.CharacterName, profile.Age, @@ -154,7 +159,8 @@ namespace Content.Server.Preferences Color.FromHex(profile.SkinColor) ), jobs, - (PreferenceUnavailableMode) profile.PreferenceUnavailable + (PreferenceUnavailableMode) profile.PreferenceUnavailable, + antags.ToList() ); } } diff --git a/Content.Server/ServerContentIoC.cs b/Content.Server/ServerContentIoC.cs index 4e58f6379e..5af7382d2c 100644 --- a/Content.Server/ServerContentIoC.cs +++ b/Content.Server/ServerContentIoC.cs @@ -34,6 +34,7 @@ namespace Content.Server IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); } diff --git a/Content.Server/Utility/InteractionChecks.cs b/Content.Server/Utility/InteractionChecks.cs index 17fdf6f54b..b79952a5bb 100644 --- a/Content.Server/Utility/InteractionChecks.cs +++ b/Content.Server/Utility/InteractionChecks.cs @@ -1,6 +1,7 @@ using System; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Shared.Interfaces; using Content.Shared.Physics; using Robust.Shared.GameObjects.Systems; @@ -22,14 +23,15 @@ namespace Content.Server.Utility /// /// Default interaction check for targeted attack interaction types. - /// Same as , but defaults to allow inside blockers. + /// Same as , but defaults to ignore inside blockers + /// (making the check less restrictive). /// Validates that attacker is in range of the attacked entity. Additionally shows a popup if /// validation fails. /// - public static bool InRangeUnobstructed(ITargetedInteractEventArgs eventArgs, bool insideBlockerValid = true) + public static bool InRangeUnobstructed(ITargetedInteractEventArgs eventArgs, bool ignoreInsideBlocker = true) { if (!EntitySystem.Get().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, - eventArgs.Target.Transform.MapPosition, ignoredEnt: eventArgs.Target, insideBlockerValid: insideBlockerValid)) + eventArgs.Target.Transform.MapPosition, ignoredEnt: eventArgs.Target, ignoreInsideBlocker: ignoreInsideBlocker)) { var localizationManager = IoCManager.Resolve(); eventArgs.Target.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); @@ -39,19 +41,46 @@ namespace Content.Server.Utility return true; } + /// + /// Default interaction check for Drag drop interaction types. + /// Same as , but defaults to ignore inside blockers + /// (making the check less restrictive) and checks reachability of both the target and the dragged / dropped object. + /// Additionally shows a popup if validation fails. + /// + public static bool InRangeUnobstructed(DragDropEventArgs eventArgs, bool ignoreInsideBlocker = true) + { + if (!EntitySystem.Get().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, + eventArgs.Target.Transform.MapPosition, ignoredEnt: eventArgs.Target, ignoreInsideBlocker: ignoreInsideBlocker)) + { + var localizationManager = IoCManager.Resolve(); + eventArgs.Target.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); + return false; + } + if (!EntitySystem.Get().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, + eventArgs.Dropped.Transform.MapPosition, ignoredEnt: eventArgs.Dropped, ignoreInsideBlocker: ignoreInsideBlocker)) + { + var localizationManager = IoCManager.Resolve(); + eventArgs.Dropped.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); + return false; + } + + return true; + } + /// /// Default interaction check for after attack interaction types. - /// Same as , but defaults to allow inside blockers. + /// Same as , but defaults to ignore inside blockers + /// (making the check less restrictive). /// Validates that attacker is in range of the attacked entity, if there is such an entity. /// If there is no attacked entity, validates that they are in range of the clicked position. /// Additionally shows a popup if validation fails. /// - public static bool InRangeUnobstructed(AfterInteractEventArgs eventArgs, bool insideBlockerValid = true) + public static bool InRangeUnobstructed(AfterInteractEventArgs eventArgs, bool ignoreInsideBlocker = true) { if (eventArgs.Target != null) { if (!EntitySystem.Get().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, - eventArgs.Target.Transform.MapPosition, ignoredEnt: eventArgs.Target, insideBlockerValid: insideBlockerValid)) + eventArgs.Target.Transform.MapPosition, ignoredEnt: eventArgs.Target, ignoreInsideBlocker: ignoreInsideBlocker)) { var localizationManager = IoCManager.Resolve(); eventArgs.Target.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); @@ -61,7 +90,7 @@ namespace Content.Server.Utility else { if (!EntitySystem.Get().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, - eventArgs.ClickLocation.ToMap(IoCManager.Resolve()), ignoredEnt: eventArgs.User, insideBlockerValid: insideBlockerValid)) + eventArgs.ClickLocation.ToMap(IoCManager.Resolve()), ignoredEnt: eventArgs.User, ignoreInsideBlocker: ignoreInsideBlocker)) { var localizationManager = IoCManager.Resolve(); eventArgs.User.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); @@ -80,12 +109,12 @@ namespace Content.Server.Utility public static bool InRangeUnobstructed(IEntity user, MapCoordinates otherCoords, float range = SharedInteractionSystem.InteractionRange, int collisionMask = (int) CollisionGroup.Impassable, IEntity ignoredEnt = null, - bool insideBlockerValid = false) + bool ignoreInsideBlocker = false) { var mapManager = IoCManager.Resolve(); var interactionSystem = EntitySystem.Get(); if (!interactionSystem.InRangeUnobstructed(user.Transform.MapPosition, otherCoords, range, collisionMask, - ignoredEnt, insideBlockerValid)) + ignoredEnt, ignoreInsideBlocker)) { var localizationManager = IoCManager.Resolve(); user.PopupMessage(user, localizationManager.GetString("You can't reach there!")); diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs index 07b2b839c2..fd68608336 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs @@ -1,6 +1,14 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; +using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Timers; +using Robust.Shared.ViewVariables; +using YamlDotNet.RepresentationModel; +using Component = Robust.Shared.GameObjects.Component; namespace Content.Shared.GameObjects.Components.Mobs { @@ -13,21 +21,72 @@ namespace Content.Shared.GameObjects.Components.Mobs public sealed override uint? NetID => ContentNetIDs.OVERLAYEFFECTS; } - public enum ScreenEffects + [Serializable, NetSerializable] + public class OverlayContainer { - None, - CircleMask, - GradientCircleMask, + [ViewVariables(VVAccess.ReadOnly)] + public string ID { get; } + + public OverlayContainer([NotNull] string id) + { + ID = id; + } + + public OverlayContainer(OverlayType type) : this(type.ToString()) + { + + } + + public override bool Equals(object obj) + { + if (obj is OverlayContainer container) + { + return container.ID == ID; + } + + if (obj is string idString) + { + return idString == ID; + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return (ID != null ? ID.GetHashCode() : 0); + } } [Serializable, NetSerializable] public class OverlayEffectComponentState : ComponentState { - public ScreenEffects ScreenEffect; + public List Overlays; - public OverlayEffectComponentState(ScreenEffects screenEffect) : base(ContentNetIDs.OVERLAYEFFECTS) + public OverlayEffectComponentState(List overlays) : base(ContentNetIDs.OVERLAYEFFECTS) { - ScreenEffect = screenEffect; + Overlays = overlays; } } + + [Serializable, NetSerializable] + public class TimedOverlayContainer : OverlayContainer + { + [ViewVariables(VVAccess.ReadOnly)] + public int Length { get; } + + public TimedOverlayContainer(string id, int length) : base(id) + { + Length = length; + } + + public void StartTimer(Action finished) => Timer.Spawn(Length, finished); + } + + public enum OverlayType + { + GradientCircleMaskOverlay, + CircleMaskOverlay, + FlashOverlay + } } diff --git a/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs b/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs index 3074a970fd..975a2c6477 100644 --- a/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs +++ b/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs @@ -45,7 +45,7 @@ namespace Content.Shared.GameObjects.Components.Movement /// /// Toggles one of the four cardinal directions. Each of the four directions are - /// composed into a single direction vector, . Enabling + /// composed into a single direction vector, . Enabling /// opposite directions will cancel each other out, resulting in no direction. /// /// Direction to toggle. diff --git a/Content.Shared/GameObjects/Components/SharedPlaceableSurfaceComponent.cs b/Content.Shared/GameObjects/Components/SharedPlaceableSurfaceComponent.cs new file mode 100644 index 0000000000..2461021357 --- /dev/null +++ b/Content.Shared/GameObjects/Components/SharedPlaceableSurfaceComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.Components +{ + public abstract class SharedPlaceableSurfaceComponent : Component + { + public override string Name => "PlaceableSurface"; + } +} diff --git a/Content.Shared/GameObjects/Components/Strap/SharedStrapComponent.cs b/Content.Shared/GameObjects/Components/Strap/SharedStrapComponent.cs index febdbbb3e8..4ec1463c1a 100644 --- a/Content.Shared/GameObjects/Components/Strap/SharedStrapComponent.cs +++ b/Content.Shared/GameObjects/Components/Strap/SharedStrapComponent.cs @@ -26,12 +26,27 @@ namespace Content.Shared.GameObjects.Components.Strap { public sealed override string Name => "Strap"; - public virtual StrapPosition Position { get; set; } + public sealed override uint? NetID => ContentNetIDs.STRAP; - [Serializable, NetSerializable] - public enum StrapVisuals + public abstract StrapPosition Position { get; protected set; } + } + + [Serializable, NetSerializable] + public sealed class StrapComponentState : ComponentState + { + public readonly StrapPosition Position; + + public StrapComponentState(StrapPosition position) : base(ContentNetIDs.BUCKLE) { - RotationAngle + Position = position; } + + public bool Buckled { get; } + } + + [Serializable, NetSerializable] + public enum StrapVisuals + { + RotationAngle } } diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 566185c7e8..3d2dc7e9b3 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -59,6 +59,7 @@ public const uint BUCKLE = 1052; public const uint PROJECTILE = 1053; public const uint THROWN_ITEM = 1054; + public const uint STRAP = 1055; // Net IDs for integration tests. public const uint PREDICTION_TEST = 10001; diff --git a/Content.Shared/GameObjects/EntitySystemMessages/DragDropMessage.cs b/Content.Shared/GameObjects/EntitySystemMessages/DragDropMessage.cs new file mode 100644 index 0000000000..8b5648e401 --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/DragDropMessage.cs @@ -0,0 +1,25 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.EntitySystemMessages +{ + /// + /// Requests a drag / drop interaction to be performed + /// + [Serializable, NetSerializable] + public class DragDropMessage : EntitySystemMessage + { + public GridCoordinates DropLocation { get; } + public EntityUid Dropped { get; } + public EntityUid Target { get; } + + public DragDropMessage(GridCoordinates dropLocation, EntityUid dropped, EntityUid target) + { + DropLocation = dropLocation; + Dropped = dropped; + Target = target; + } + } +} diff --git a/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs b/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs index 80f4c88e7c..9b1946fc6f 100644 --- a/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs +++ b/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs @@ -2,7 +2,6 @@ using Content.Shared.GameObjects.Components.Mobs; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Utility; namespace Content.Shared.GameObjects.EntitySystems { @@ -31,7 +30,7 @@ namespace Content.Shared.GameObjects.EntitySystems return EntitySystem.Get() .InRangeUnobstructed(examiner.Transform.MapPosition, examined.Transform.MapPosition, - ExamineRange, predicate: entity => entity == examiner || entity == examined, insideBlockerValid:true); + ExamineRange, predicate: entity => entity == examiner || entity == examined, ignoreInsideBlocker:true); } } } diff --git a/Content.Shared/GameObjects/EntitySystems/SharedInteractionSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedInteractionSystem.cs index 872cddbc5f..ca1fc0a5b9 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedInteractionSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SharedInteractionSystem.cs @@ -72,10 +72,13 @@ namespace Content.Shared.GameObjects.EntitySystems /// maximum distance between the two sets of coordinates. /// the mask to check for collisions /// A predicate to check whether to ignore an entity or not. If it returns true, it will be ignored. - /// if coordinates inside obstructions count as obstructed or not + /// if true and the coordinates are inside the obstruction, ignores the obstruction and + /// considers the interaction unobstructed. Therefore, setting this to true makes this check more permissive, such + /// as allowing an interaction to occur inside something impassable (like a wall). The default, false, + /// makes the check more restrictive. /// True if the two points are within a given range without being obstructed. public bool InRangeUnobstructed(MapCoordinates coords, MapCoordinates otherCoords, float range = InteractionRange, - int collisionMask = (int)CollisionGroup.Impassable, Func predicate = null, bool insideBlockerValid = false) + int collisionMask = (int)CollisionGroup.Impassable, Func predicate = null, bool ignoreInsideBlocker = false) { if (!coords.InRange(otherCoords, range)) return false; @@ -87,7 +90,7 @@ namespace Content.Shared.GameObjects.EntitySystems var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask); var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, returnOnFirstHit: false).ToList(); - return rayResults.Count == 0 || (insideBlockerValid && rayResults.Count > 0 && (rayResults[0].HitPos - otherCoords.Position).Length < 1f); + return rayResults.Count == 0 || (ignoreInsideBlocker && rayResults.Count > 0 && (rayResults[0].HitPos - otherCoords.Position).Length < 1f); } /// @@ -101,11 +104,14 @@ namespace Content.Shared.GameObjects.EntitySystems /// maximum distance between the two sets of coordinates. /// the mask to check for collisions /// the entity to be ignored when checking for collisions. - /// if coordinates inside obstructions count as obstructed or not + /// if true and the coordinates are inside the obstruction, ignores the obstruction and + /// considers the interaction unobstructed. Therefore, setting this to true makes this check more permissive, such + /// as allowing an interaction to occur inside something impassable (like a wall). The default, false, + /// makes the check more restrictive. /// True if the two points are within a given range without being obstructed. public bool InRangeUnobstructed(MapCoordinates coords, MapCoordinates otherCoords, float range = InteractionRange, - int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null, bool insideBlockerValid = false) => + int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null, bool ignoreInsideBlocker = false) => InRangeUnobstructed(coords, otherCoords, range, collisionMask, - ignoredEnt == null ? null : (Func)(entity => ignoredEnt == entity), insideBlockerValid); + ignoredEnt == null ? null : (Func)(entity => ignoredEnt == entity), ignoreInsideBlocker); } } diff --git a/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs index 6df3b87d19..931648c5f1 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs @@ -54,7 +54,6 @@ namespace Content.Shared.GameObjects.EntitySystems base.Shutdown(); } - protected void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, PhysicsComponent physics, CollidableComponent? collider = null) { diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index d44cb1d64d..bdbc7cee49 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -11,6 +11,7 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction Drop = "Drop"; public static readonly BoundKeyFunction ExamineEntity = "ExamineEntity"; public static readonly BoundKeyFunction FocusChat = "FocusChatWindow"; + public static readonly BoundKeyFunction FocusOOC = "FocusOOCWindow"; public static readonly BoundKeyFunction OpenCharacterMenu = "OpenCharacterMenu"; public static readonly BoundKeyFunction OpenContextMenu = "OpenContextMenu"; public static readonly BoundKeyFunction OpenCraftingMenu = "OpenCraftingMenu"; diff --git a/Content.Shared/Interfaces/IConfigurable.cs b/Content.Shared/Interfaces/IConfigurable.cs new file mode 100644 index 0000000000..17fbe07880 --- /dev/null +++ b/Content.Shared/Interfaces/IConfigurable.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Interfaces +{ + public interface IConfigurable + { + public void Configure(T parameters); + } +} diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 5b061d5a3f..db068e358d 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Content.Shared.Antags; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Preferences @@ -9,6 +12,7 @@ namespace Content.Shared.Preferences public class HumanoidCharacterProfile : ICharacterProfile { private readonly Dictionary _jobPriorities; + private readonly List _antagPreferences; public static int MinimumAge = 18; public static int MaximumAge = 90; @@ -18,7 +22,8 @@ namespace Content.Shared.Preferences Sex sex, HumanoidCharacterAppearance appearance, Dictionary jobPriorities, - PreferenceUnavailableMode preferenceUnavailable) + PreferenceUnavailableMode preferenceUnavailable, + List antagPreferences) { Name = name; Age = age; @@ -26,6 +31,7 @@ namespace Content.Shared.Preferences Appearance = appearance; _jobPriorities = jobPriorities; PreferenceUnavailable = preferenceUnavailable; + _antagPreferences = antagPreferences; } public HumanoidCharacterProfile( @@ -34,9 +40,10 @@ namespace Content.Shared.Preferences Sex sex, HumanoidCharacterAppearance appearance, IReadOnlyDictionary jobPriorities, - PreferenceUnavailableMode preferenceUnavailable) + PreferenceUnavailableMode preferenceUnavailable, + IReadOnlyList antagPreferences) : this(name, age, sex, appearance, new Dictionary(jobPriorities), - preferenceUnavailable) + preferenceUnavailable, new List(antagPreferences)) { } @@ -46,7 +53,7 @@ namespace Content.Shared.Preferences new Dictionary { {SharedGameTicker.OverflowJob, JobPriority.High} - }, PreferenceUnavailableMode.StayInLobby); + }, PreferenceUnavailableMode.StayInLobby, new List()); } public string Name { get; } @@ -55,26 +62,27 @@ namespace Content.Shared.Preferences public ICharacterAppearance CharacterAppearance => Appearance; public HumanoidCharacterAppearance Appearance { get; } public IReadOnlyDictionary JobPriorities => _jobPriorities; + public IReadOnlyList AntagPreferences => _antagPreferences; public PreferenceUnavailableMode PreferenceUnavailable { get; } public HumanoidCharacterProfile WithName(string name) { - return new HumanoidCharacterProfile(name, Age, Sex, Appearance, _jobPriorities, PreferenceUnavailable); + return new HumanoidCharacterProfile(name, Age, Sex, Appearance, _jobPriorities, PreferenceUnavailable, _antagPreferences); } public HumanoidCharacterProfile WithAge(int age) { - return new HumanoidCharacterProfile(Name, age, Sex, Appearance, _jobPriorities, PreferenceUnavailable); + return new HumanoidCharacterProfile(Name, age, Sex, Appearance, _jobPriorities, PreferenceUnavailable, _antagPreferences); } public HumanoidCharacterProfile WithSex(Sex sex) { - return new HumanoidCharacterProfile(Name, Age, sex, Appearance, _jobPriorities, PreferenceUnavailable); + return new HumanoidCharacterProfile(Name, Age, sex, Appearance, _jobPriorities, PreferenceUnavailable, _antagPreferences); } public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance) { - return new HumanoidCharacterProfile(Name, Age, Sex, appearance, _jobPriorities, PreferenceUnavailable); + return new HumanoidCharacterProfile(Name, Age, Sex, appearance, _jobPriorities, PreferenceUnavailable, _antagPreferences); } public HumanoidCharacterProfile WithJobPriorities(IReadOnlyDictionary jobPriorities) @@ -85,7 +93,8 @@ namespace Content.Shared.Preferences Sex, Appearance, new Dictionary(jobPriorities), - PreferenceUnavailable); + PreferenceUnavailable, + _antagPreferences); } public HumanoidCharacterProfile WithJobPriority(string jobId, JobPriority priority) @@ -100,12 +109,44 @@ namespace Content.Shared.Preferences dictionary[jobId] = priority; } - return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, dictionary, PreferenceUnavailable); + return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, dictionary, PreferenceUnavailable, _antagPreferences); } public HumanoidCharacterProfile WithPreferenceUnavailable(PreferenceUnavailableMode mode) { - return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, _jobPriorities, mode); + return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, _jobPriorities, mode, _antagPreferences); + } + + public HumanoidCharacterProfile WithAntagPreferences(IReadOnlyList antagPreferences) + { + return new HumanoidCharacterProfile( + Name, + Age, + Sex, + Appearance, + _jobPriorities, + PreferenceUnavailable, + new List(antagPreferences)); + } + + public HumanoidCharacterProfile WithAntagPreference(string antagId, bool pref) + { + var list = new List(_antagPreferences); + if(pref) + { + if(!list.Contains(antagId)) + { + list.Add(antagId); + } + } + else + { + if(list.Contains(antagId)) + { + list.Remove(antagId); + } + } + return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, _jobPriorities, PreferenceUnavailable, list); } public string Summary => @@ -119,6 +160,7 @@ namespace Content.Shared.Preferences if (Sex != other.Sex) return false; if (PreferenceUnavailable != other.PreferenceUnavailable) return false; if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false; + if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false; return Appearance.MemberwiseEquals(other.Appearance); } } diff --git a/Content.Shared/Roles/AntagPrototype.cs b/Content.Shared/Roles/AntagPrototype.cs new file mode 100644 index 0000000000..a253d13a1a --- /dev/null +++ b/Content.Shared/Roles/AntagPrototype.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Robust.Shared.Localization; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Antags +{ + /// + /// Describes information for a single antag. + /// + [Prototype("antag")] + public class AntagPrototype : IPrototype, IIndexedPrototype + { + public string ID { get; private set; } + + /// + /// The name of this antag as displayed to players. + /// + public string Name { get; private set; } + + /// + /// The antag's objective, displayed at round-start to the player. + /// + public string Objective { get; private set; } + + /// + /// Whether or not the antag role is one of the bad guys. + /// + public bool Antagonist { get; private set; } + + /// + /// Whether or not the player can set the antag role in antag preferences. + /// + public bool SetPreference { get; private set; } + + public void LoadFrom(YamlMappingNode mapping) + { + ID = mapping.GetNode("id").AsString(); + Name = Loc.GetString(mapping.GetNode("name").ToString()); + Objective = mapping.GetNode("objective").ToString(); + Antagonist = mapping.GetNode("antagonist").AsBool(); + SetPreference = mapping.GetNode("setPreference").AsBool(); + } + } +} diff --git a/Content.Shared/Jobs/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs similarity index 100% rename from Content.Shared/Jobs/JobPrototype.cs rename to Content.Shared/Roles/JobPrototype.cs diff --git a/Content.Shared/Jobs/StartingGearPrototype.cs b/Content.Shared/Roles/StartingGearPrototype.cs similarity index 100% rename from Content.Shared/Jobs/StartingGearPrototype.cs rename to Content.Shared/Roles/StartingGearPrototype.cs diff --git a/Content.Tests/Server/Preferences/PreferencesDatabaseTests.cs b/Content.Tests/Server/Preferences/PreferencesDatabaseTests.cs index b0a087a5db..1aa4353c10 100644 --- a/Content.Tests/Server/Preferences/PreferencesDatabaseTests.cs +++ b/Content.Tests/Server/Preferences/PreferencesDatabaseTests.cs @@ -35,7 +35,8 @@ namespace Content.Tests.Server.Preferences { {SharedGameTicker.OverflowJob, JobPriority.High} }, - PreferenceUnavailableMode.StayInLobby + PreferenceUnavailableMode.StayInLobby, + new List{} ); } diff --git a/Resources/Audio/weapons/flash.ogg b/Resources/Audio/weapons/flash.ogg new file mode 100644 index 0000000000..eed2ed0d52 Binary files /dev/null and b/Resources/Audio/weapons/flash.ogg differ diff --git a/Resources/Groups/groups.yml b/Resources/Groups/groups.yml index d1b4d32d96..dc76b17683 100644 --- a/Resources/Groups/groups.yml +++ b/Resources/Groups/groups.yml @@ -74,6 +74,8 @@ - mindinfo - addrole - rmrole + - addoverlay + - rmoverlay - showtime - group - addai @@ -121,6 +123,8 @@ - mindinfo - addrole - rmrole + - addoverlay + - rmoverlay - srvpopupmsg - group - showtime diff --git a/Resources/Prototypes/Entities/Buildings/Storage/StorageTanks/fuel_tank.yml b/Resources/Prototypes/Entities/Buildings/Storage/StorageTanks/fuel_tank.yml index 0f032dcf45..55a315154b 100644 --- a/Resources/Prototypes/Entities/Buildings/Storage/StorageTanks/fuel_tank.yml +++ b/Resources/Prototypes/Entities/Buildings/Storage/StorageTanks/fuel_tank.yml @@ -18,3 +18,8 @@ reagents: - ReagentId: chem.WeldingFuel Quantity: 1500 + - type: DamageOnToolInteract + damage: 200 + tools: + - Welding + diff --git a/Resources/Prototypes/Entities/Items/Weapons/security.yml b/Resources/Prototypes/Entities/Items/Weapons/security.yml index 43e28a9ef7..957bab088b 100644 --- a/Resources/Prototypes/Entities/Items/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Items/Weapons/security.yml @@ -23,3 +23,30 @@ HeldPrefix: off - type: ItemCooldown + +- type: entity + name: flash + parent: BaseItem + id: Flash + components: + - type: Sprite + sprite: Objects/Melee/flash.rsi + state: flash + + - type: Icon + sprite: Objects/Melee/flash.rsi + state: flash + + - type: Flash + damage: 0 + cooldownTime: 1 + arc: smash + hitSound: /Audio/weapons/flash.ogg + slowTo: 0.7 + + - type: Item + Size: 2 + sprite: Objects/Melee/flash.rsi + + - type: ItemCooldown + diff --git a/Resources/Prototypes/Entities/Markers/drag_shadow.yml b/Resources/Prototypes/Entities/Markers/drag_shadow.yml new file mode 100644 index 0000000000..29643c4204 --- /dev/null +++ b/Resources/Prototypes/Entities/Markers/drag_shadow.yml @@ -0,0 +1,7 @@ +- type: entity + name: drag shadow + id: dragshadow + components: + - type: Sprite + layers: + - shader: unshaded diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 8995218961..129866f5bd 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -2,7 +2,6 @@ save: false name: Urist McHands parent: BaseHumanMob_Content - abstract: true id: HumanMob_Content description: A miserable pile of secrets drawdepth: Mobs @@ -17,4 +16,4 @@ zoom: 0.5, 0.5 - type: CameraRecoil - type: Examiner - - type: HumanInventoryController \ No newline at end of file + - type: HumanInventoryController diff --git a/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionInnocent.yml b/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionInnocent.yml new file mode 100644 index 0000000000..92c73b550f --- /dev/null +++ b/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionInnocent.yml @@ -0,0 +1,6 @@ +- type: antag + id: SuspicionInnocent + name: "innocent" + antagonist: false + setPreference: false + objective: "Discover and eliminate all traitors." diff --git a/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionTraitor.yml b/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionTraitor.yml new file mode 100644 index 0000000000..1d2168232c --- /dev/null +++ b/Resources/Prototypes/Roles/Antags/Suspicion/SuspicionTraitor.yml @@ -0,0 +1,6 @@ +- type: antag + id: SuspicionTraitor + name: "traitor" + antagonist: true + setPreference: true + objective: "Kill the innocents." diff --git a/Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml b/Resources/Prototypes/Roles/Jobs/Cargo/CargoTechnician.yml similarity index 100% rename from Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml rename to Resources/Prototypes/Roles/Jobs/Cargo/CargoTechnician.yml diff --git a/Resources/Prototypes/Jobs/Civilian/Assistant.yml b/Resources/Prototypes/Roles/Jobs/Civilian/Assistant.yml similarity index 100% rename from Resources/Prototypes/Jobs/Civilian/Assistant.yml rename to Resources/Prototypes/Roles/Jobs/Civilian/Assistant.yml diff --git a/Resources/Prototypes/Jobs/Civilian/Bartender.yml b/Resources/Prototypes/Roles/Jobs/Civilian/Bartender.yml similarity index 100% rename from Resources/Prototypes/Jobs/Civilian/Bartender.yml rename to Resources/Prototypes/Roles/Jobs/Civilian/Bartender.yml diff --git a/Resources/Prototypes/Jobs/Civilian/Chef.yml b/Resources/Prototypes/Roles/Jobs/Civilian/Chef.yml similarity index 100% rename from Resources/Prototypes/Jobs/Civilian/Chef.yml rename to Resources/Prototypes/Roles/Jobs/Civilian/Chef.yml diff --git a/Resources/Prototypes/Jobs/Civilian/Clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/Clown.yml similarity index 100% rename from Resources/Prototypes/Jobs/Civilian/Clown.yml rename to Resources/Prototypes/Roles/Jobs/Civilian/Clown.yml diff --git a/Resources/Prototypes/Jobs/Civilian/Janitor.yml b/Resources/Prototypes/Roles/Jobs/Civilian/Janitor.yml similarity index 100% rename from Resources/Prototypes/Jobs/Civilian/Janitor.yml rename to Resources/Prototypes/Roles/Jobs/Civilian/Janitor.yml diff --git a/Resources/Prototypes/Jobs/Command/captain.yml b/Resources/Prototypes/Roles/Jobs/Command/captain.yml similarity index 100% rename from Resources/Prototypes/Jobs/Command/captain.yml rename to Resources/Prototypes/Roles/Jobs/Command/captain.yml diff --git a/Resources/Prototypes/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml similarity index 100% rename from Resources/Prototypes/Jobs/Command/head_of_personnel.yml rename to Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml diff --git a/Resources/Prototypes/Jobs/Engineering/chief_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml similarity index 100% rename from Resources/Prototypes/Jobs/Engineering/chief_engineer.yml rename to Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml diff --git a/Resources/Prototypes/Jobs/Engineering/station_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml similarity index 100% rename from Resources/Prototypes/Jobs/Engineering/station_engineer.yml rename to Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml diff --git a/Resources/Prototypes/Jobs/Medical/chief_medical_officer.yml b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml similarity index 100% rename from Resources/Prototypes/Jobs/Medical/chief_medical_officer.yml rename to Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml diff --git a/Resources/Prototypes/Jobs/Medical/medical_doctor.yml b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml similarity index 100% rename from Resources/Prototypes/Jobs/Medical/medical_doctor.yml rename to Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml diff --git a/Resources/Prototypes/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml similarity index 100% rename from Resources/Prototypes/Jobs/Science/research_director.yml rename to Resources/Prototypes/Roles/Jobs/Science/research_director.yml diff --git a/Resources/Prototypes/Jobs/Science/scientist.yml b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml similarity index 100% rename from Resources/Prototypes/Jobs/Science/scientist.yml rename to Resources/Prototypes/Roles/Jobs/Science/scientist.yml diff --git a/Resources/Prototypes/Jobs/Security/head_of_security.yml b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml similarity index 100% rename from Resources/Prototypes/Jobs/Security/head_of_security.yml rename to Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml diff --git a/Resources/Prototypes/Jobs/Security/security_officer.yml b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml similarity index 100% rename from Resources/Prototypes/Jobs/Security/security_officer.yml rename to Resources/Prototypes/Roles/Jobs/Security/security_officer.yml diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml index e278d35c9a..b206811bc0 100644 --- a/Resources/Prototypes/Shaders/shaders.yml +++ b/Resources/Prototypes/Shaders/shaders.yml @@ -7,3 +7,8 @@ id: GradientCircleMask kind: source path: "/Shaders/gradient_circle_mask.swsl" + +- type: shader + id: FlashedEffect + kind: source + path: "/Shaders/flashed_effect.swsl" diff --git a/Resources/Shaders/flashed_effect.swsl b/Resources/Shaders/flashed_effect.swsl new file mode 100644 index 0000000000..fdbe860cb7 --- /dev/null +++ b/Resources/Shaders/flashed_effect.swsl @@ -0,0 +1,18 @@ +uniform float percentComplete; +uniform float fadeFalloffExp = 8; + +void fragment() { + // Higher exponent -> stronger blinding effect + float remaining = -pow(percentComplete, fadeFalloffExp) + 1; + + // Two ghost textures that spin around the character + vec4 tex1 = texture(TEXTURE, vec2(UV.x + (0.02) * sin(TIME * 3), UV.y + (0.02) * cos(TIME * 3))); + vec4 tex2 = texture(TEXTURE, vec2(UV.x + (0.01) * sin(TIME * 2), UV.y + (0.01) * cos(TIME * 2))); + + vec4 textureMix = mix(tex1, tex2, 0.5); + + // Gradually mixes between the texture mix and a full-white texture, causing the "blinding" effect + vec4 mixed = mix(vec4(1, 1, 1, 1), textureMix, percentComplete); + + COLOR = vec4(mixed.rgb, remaining); +} diff --git a/Resources/Textures/Objects/Melee/flash.rsi/burnt.png b/Resources/Textures/Objects/Melee/flash.rsi/burnt.png new file mode 100644 index 0000000000..b35979f0f7 Binary files /dev/null and b/Resources/Textures/Objects/Melee/flash.rsi/burnt.png differ diff --git a/Resources/Textures/Objects/Melee/flash.rsi/flash.png b/Resources/Textures/Objects/Melee/flash.rsi/flash.png new file mode 100644 index 0000000000..a5afbcdae9 Binary files /dev/null and b/Resources/Textures/Objects/Melee/flash.rsi/flash.png differ diff --git a/Resources/Textures/Objects/Melee/flash.rsi/flashing.png b/Resources/Textures/Objects/Melee/flash.rsi/flashing.png new file mode 100644 index 0000000000..0508c02541 Binary files /dev/null and b/Resources/Textures/Objects/Melee/flash.rsi/flashing.png differ diff --git a/Resources/Textures/Objects/Melee/flash.rsi/inhand-left.png b/Resources/Textures/Objects/Melee/flash.rsi/inhand-left.png new file mode 100644 index 0000000000..950195a37d Binary files /dev/null and b/Resources/Textures/Objects/Melee/flash.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Melee/flash.rsi/inhand-right.png b/Resources/Textures/Objects/Melee/flash.rsi/inhand-right.png new file mode 100644 index 0000000000..7a17666d9c Binary files /dev/null and b/Resources/Textures/Objects/Melee/flash.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Melee/flash.rsi/meta.json b/Resources/Textures/Objects/Melee/flash.rsi/meta.json new file mode 100644 index 0000000000..c0299aa63d --- /dev/null +++ b/Resources/Textures/Objects/Melee/flash.rsi/meta.json @@ -0,0 +1,76 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC BY-SA 3.0", + "copyright": "Taken from CEV Eris", + "states": [ + { + "name": "flash", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "flashing", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.3 + ] + ] + }, + { + "name": "burnt", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-right", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + } + ] +} diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 29388101ed..5c2a9da3c3 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -43,6 +43,9 @@ binds: - function: FocusChatWindow type: State key: T +- function: FocusOOCWindow + type: State + key: LBracket - function: EditorLinePlace type: State key: MouseLeft diff --git a/RobustToolbox b/RobustToolbox index 2d7192d79d..cc9391c029 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 2d7192d79dfc3e74607a66cb1d5bb155ac955ec3 +Subproject commit cc9391c029e155b2ef4ec7b89230e64ed69d4e47