diff --git a/Content.Client/Atmos/AtmosDebugOverlay.cs b/Content.Client/Atmos/AtmosDebugOverlay.cs index dacf02231e..728257d448 100644 --- a/Content.Client/Atmos/AtmosDebugOverlay.cs +++ b/Content.Client/Atmos/AtmosDebugOverlay.cs @@ -6,6 +6,8 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Enums; +using System; namespace Content.Client.Atmos { @@ -19,7 +21,7 @@ namespace Content.Client.Atmos public override OverlaySpace Space => OverlaySpace.WorldSpace; - public AtmosDebugOverlay() : base(nameof(AtmosDebugOverlay)) + public AtmosDebugOverlay() { IoCManager.InjectDependencies(this); diff --git a/Content.Client/Atmos/GasTileOverlay.cs b/Content.Client/Atmos/GasTileOverlay.cs index 4d71641ff4..296afc6527 100644 --- a/Content.Client/Atmos/GasTileOverlay.cs +++ b/Content.Client/Atmos/GasTileOverlay.cs @@ -1,4 +1,5 @@ -using Content.Client.GameObjects.EntitySystems; +using Content.Client.GameObjects.EntitySystems; +using Robust.Shared.Enums; using Robust.Client.Graphics; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -15,9 +16,9 @@ namespace Content.Client.Atmos [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IClyde _clyde = default!; - public override OverlaySpace Space => OverlaySpace.WorldSpace; + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV; - public GasTileOverlay() : base(nameof(GasTileOverlay)) + public GasTileOverlay() { IoCManager.InjectDependencies(this); diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index d77639501b..61bdc03b9f 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Client.Administration; using Content.Client.Changelog; using Content.Client.Eui; @@ -152,12 +152,15 @@ namespace Content.Client IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + var overlayMgr = IoCManager.Resolve(); overlayMgr.AddOverlay(new ParallaxOverlay()); - overlayMgr.AddOverlay(new GradientCircleMaskOverlay()); + overlayMgr.AddOverlay(new SingularityOverlay()); + overlayMgr.AddOverlay(new CritOverlay()); //Hopefully we can cut down on this list... don't see why a death overlay needs to be instantiated here. overlayMgr.AddOverlay(new CircleMaskOverlay()); overlayMgr.AddOverlay(new FlashOverlay()); overlayMgr.AddOverlay(new RadiationPulseOverlay()); + IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); diff --git a/Content.Client/GameObjects/Components/Singularity/ClientSingularityComponent.cs b/Content.Client/GameObjects/Components/Singularity/ClientSingularityComponent.cs new file mode 100644 index 0000000000..2859fea072 --- /dev/null +++ b/Content.Client/GameObjects/Components/Singularity/ClientSingularityComponent.cs @@ -0,0 +1,33 @@ +using Content.Shared.GameObjects.Components.Singularity; +using Robust.Shared.GameObjects; + + +namespace Content.Client.GameObjects.Components.Singularity +{ + [RegisterComponent] + [ComponentReference(typeof(IClientSingularityInstance))] + class ClientSingularityComponent : SharedSingularityComponent, IClientSingularityInstance + { + public int Level + { + get + { + return _level; + } + set + { + _level = value; + } + } + private int _level; + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + if (curState is not SingularityComponentState state) + { + return; + } + _level = state.Level; + } + } +} diff --git a/Content.Client/GameObjects/Components/Singularity/ISingularity.cs b/Content.Client/GameObjects/Components/Singularity/ISingularity.cs new file mode 100644 index 0000000000..fe5d9b2be1 --- /dev/null +++ b/Content.Client/GameObjects/Components/Singularity/ISingularity.cs @@ -0,0 +1,11 @@ + + + + +namespace Content.Client.GameObjects.Components.Singularity +{ + interface IClientSingularityInstance + { + public int Level { get; set; } + } +} diff --git a/Content.Client/GameObjects/Components/Singularity/ToySingularityComponent.cs b/Content.Client/GameObjects/Components/Singularity/ToySingularityComponent.cs new file mode 100644 index 0000000000..4711d36c30 --- /dev/null +++ b/Content.Client/GameObjects/Components/Singularity/ToySingularityComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.Singularity +{ + + [RegisterComponent] + [ComponentReference(typeof(IClientSingularityInstance))] + public class ToySingularityComponent : Component, IClientSingularityInstance + { + public override string Name => "ToySingularity"; + public int Level { + get { + return 1; + } + set { + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs b/Content.Client/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs index 949ef207df..508079b816 100644 --- a/Content.Client/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs +++ b/Content.Client/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System.Collections.Generic; using Content.Client.UserInterface; using Content.Client.UserInterface.Suspicion; @@ -68,7 +68,7 @@ namespace Content.Client.GameObjects.Components.Suspicion private void AddTraitorOverlay() { - if (_overlayManager.HasOverlay(nameof(TraitorOverlay))) + if (_overlayManager.HasOverlay()) { return; } @@ -85,7 +85,7 @@ namespace Content.Client.GameObjects.Components.Suspicion return; } - _overlayManager.RemoveOverlay(nameof(TraitorOverlay)); + _overlayManager.RemoveOverlay(); } public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) diff --git a/Content.Client/GameObjects/Components/Suspicion/TraitorOverlay.cs b/Content.Client/GameObjects/Components/Suspicion/TraitorOverlay.cs index be5c76a84d..331c56828e 100644 --- a/Content.Client/GameObjects/Components/Suspicion/TraitorOverlay.cs +++ b/Content.Client/GameObjects/Components/Suspicion/TraitorOverlay.cs @@ -2,6 +2,7 @@ using Content.Shared.GameObjects.EntitySystems; using Robust.Client.Graphics; using Robust.Client.Player; using Robust.Client.ResourceManagement; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -25,7 +26,6 @@ namespace Content.Client.GameObjects.Components.Suspicion IEntityManager entityManager, IResourceCache resourceCache, IEyeManager eyeManager) - : base(nameof(TraitorOverlay)) { _playerManager = IoCManager.Resolve(); diff --git a/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs index d1e932d0c4..86e31dd55f 100644 --- a/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs +++ b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs @@ -1,8 +1,10 @@ -using System; +#nullable enable +using System; using Content.Client.Graphics.Overlays; using Content.Shared.GameObjects.Components.Weapons; using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Timing; @@ -15,7 +17,7 @@ namespace Content.Client.GameObjects.Components.Weapons private TimeSpan _startTime; private double _duration; - public override void HandleComponentState(ComponentState curState, ComponentState nextState) + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) { if (curState == null) { @@ -55,7 +57,7 @@ namespace Content.Client.GameObjects.Components.Weapons _duration = newState.Duration; var overlayManager = IoCManager.Resolve(); - var overlay = overlayManager.GetOverlay(nameof(FlashOverlay)); + var overlay = overlayManager.GetOverlay(); overlay.ReceiveFlash(_duration); } } diff --git a/Content.Client/GameObjects/EntitySystems/AI/ClientPathfindingDebugSystem.cs b/Content.Client/GameObjects/EntitySystems/AI/ClientPathfindingDebugSystem.cs index aba664bf0f..1484627b37 100644 --- a/Content.Client/GameObjects/EntitySystems/AI/ClientPathfindingDebugSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/AI/ClientPathfindingDebugSystem.cs @@ -4,6 +4,7 @@ using System.Linq; using Content.Shared.AI; using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -106,7 +107,7 @@ namespace Content.Client.GameObjects.EntitySystems.AI _overlay.Modes = 0; var overlayManager = IoCManager.Resolve(); - overlayManager.RemoveOverlay(_overlay.ID); + overlayManager.RemoveOverlay(_overlay); _overlay = null; } @@ -205,7 +206,7 @@ namespace Content.Client.GameObjects.EntitySystems.AI public readonly List AStarRoutes = new(); public readonly List JpsRoutes = new(); - public DebugPathfindingOverlay() : base(nameof(DebugPathfindingOverlay)) + public DebugPathfindingOverlay() { _shader = IoCManager.Resolve().Index("unshaded").Instance(); _eyeManager = IoCManager.Resolve(); diff --git a/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs index 9c219c6600..54846755b2 100644 --- a/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs @@ -1,4 +1,5 @@ -#nullable enable +#nullable enable +using System; using System.Collections.Generic; using Content.Client.Atmos; using Content.Shared.GameObjects.EntitySystems.Atmos; @@ -43,7 +44,7 @@ namespace Content.Client.GameObjects.EntitySystems _mapManager.OnGridRemoved += OnGridRemoved; var overlayManager = IoCManager.Resolve(); - if(!overlayManager.HasOverlay(nameof(AtmosDebugOverlay))) + if(!overlayManager.HasOverlay()) overlayManager.AddOverlay(new AtmosDebugOverlay()); } @@ -62,8 +63,8 @@ namespace Content.Client.GameObjects.EntitySystems base.Shutdown(); _mapManager.OnGridRemoved -= OnGridRemoved; var overlayManager = IoCManager.Resolve(); - if(!overlayManager.HasOverlay(nameof(GasTileOverlay))) - overlayManager.RemoveOverlay(nameof(GasTileOverlay)); + if(!overlayManager.HasOverlay()) + overlayManager.RemoveOverlay(); } public void Reset() diff --git a/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs index 608a446a9d..67698402b9 100644 --- a/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using Content.Client.Atmos; @@ -88,7 +88,7 @@ namespace Content.Client.GameObjects.EntitySystems } var overlayManager = IoCManager.Resolve(); - if(!overlayManager.HasOverlay(nameof(GasTileOverlay))) + if(!overlayManager.HasOverlay()) overlayManager.AddOverlay(new GasTileOverlay()); } @@ -126,8 +126,8 @@ namespace Content.Client.GameObjects.EntitySystems base.Shutdown(); _mapManager.OnGridRemoved -= OnGridRemoved; var overlayManager = IoCManager.Resolve(); - if(!overlayManager.HasOverlay(nameof(GasTileOverlay))) - overlayManager.RemoveOverlay(nameof(GasTileOverlay)); + if(!overlayManager.HasOverlay()) + overlayManager.RemoveOverlay(); } private void OnGridRemoved(GridId gridId) diff --git a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs index fd01eeb1e2..580d7b90d8 100644 --- a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs +++ b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs @@ -1,5 +1,6 @@ -using Robust.Client.Graphics; +using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Enums; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -15,7 +16,7 @@ namespace Content.Client.Graphics.Overlays public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _shader; - public CircleMaskOverlay() : base(nameof(CircleMaskOverlay)) + public CircleMaskOverlay() { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("CircleMask").Instance(); @@ -23,7 +24,7 @@ namespace Content.Client.Graphics.Overlays protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) { - if (!GradientCircleMaskOverlay.LocalPlayerHasState(_playerManager, false, true)) + if (!CritOverlay.LocalPlayerHasState(_playerManager, false, true)) return; handle.UseShader(_shader); var worldHandle = (DrawingHandleWorld)handle; diff --git a/Content.Client/Graphics/Overlays/ColoredScreenBorderOverlay.cs b/Content.Client/Graphics/Overlays/ColoredScreenBorderOverlay.cs new file mode 100644 index 0000000000..da75dc46d2 --- /dev/null +++ b/Content.Client/Graphics/Overlays/ColoredScreenBorderOverlay.cs @@ -0,0 +1,33 @@ +#nullable enable +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using System; + +namespace Content.Client.Graphics.Overlays +{ + public class ColoredScreenBorderOverlay : Overlay + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IEyeManager _eyeManager = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpace; + private readonly ShaderInstance _shader; + + public ColoredScreenBorderOverlay() + { + IoCManager.InjectDependencies(this); + _shader = _prototypeManager.Index("ColoredScreenBorder").Instance(); + } + + protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) + { + handle.UseShader(_shader); + var worldHandle = (DrawingHandleWorld)handle; + var viewport = _eyeManager.GetWorldViewport(); + worldHandle.DrawRect(viewport, Color.White); + } + } +} diff --git a/Content.Client/Graphics/Overlays/GradientCircleMask.cs b/Content.Client/Graphics/Overlays/CritOverlay.cs similarity index 76% rename from Content.Client/Graphics/Overlays/GradientCircleMask.cs rename to Content.Client/Graphics/Overlays/CritOverlay.cs index 4fb87c0882..75d09b9750 100644 --- a/Content.Client/Graphics/Overlays/GradientCircleMask.cs +++ b/Content.Client/Graphics/Overlays/CritOverlay.cs @@ -1,25 +1,26 @@ -using Content.Shared.GameObjects.Components.Mobs.State; +using Content.Shared.GameObjects.Components.Mobs.State; using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Enums; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; namespace Content.Client.Graphics.Overlays { - public class GradientCircleMaskOverlay : Overlay + public class CritOverlay : Overlay { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; public override OverlaySpace Space => OverlaySpace.WorldSpace; - private readonly ShaderInstance _shader; + private readonly ShaderInstance _gradientCircleShader, _glowingBorderShader; - public GradientCircleMaskOverlay() : base(nameof(GradientCircleMaskOverlay)) + public CritOverlay() { IoCManager.InjectDependencies(this); - _shader = _prototypeManager.Index("GradientCircleMask").Instance(); + _gradientCircleShader = _prototypeManager.Index("GradientCircleMask").Instance(); } public static bool LocalPlayerHasState(IPlayerManager pm, bool critical, bool dead) { @@ -48,9 +49,9 @@ namespace Content.Client.Graphics.Overlays if (!LocalPlayerHasState(_playerManager, true, false)) return; - handle.UseShader(_shader); - var worldHandle = (DrawingHandleWorld)handle; + var worldHandle = (DrawingHandleWorld) handle; var viewport = _eyeManager.GetWorldViewport(); + handle.UseShader(_gradientCircleShader); worldHandle.DrawRect(viewport, Color.White); } } diff --git a/Content.Client/Graphics/Overlays/FlashOverlay.cs b/Content.Client/Graphics/Overlays/FlashOverlay.cs index 0e867b59c0..e25bbadefa 100644 --- a/Content.Client/Graphics/Overlays/FlashOverlay.cs +++ b/Content.Client/Graphics/Overlays/FlashOverlay.cs @@ -1,4 +1,5 @@ -using Robust.Client.Graphics; +using Robust.Client.Graphics; +using Robust.Shared.Enums; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -20,7 +21,7 @@ namespace Content.Client.Graphics.Overlays private double _lastsFor = 1; private Texture _screenshotTexture; - public FlashOverlay() : base(nameof(FlashOverlay)) + public FlashOverlay() { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("FlashedEffect").Instance().Duplicate(); @@ -54,10 +55,9 @@ namespace Content.Client.Graphics.Overlays } } - protected override void Dispose(bool disposing) + protected override void DisposeBehavior() { - base.Dispose(disposing); - + base.Dispose(); _screenshotTexture = null; } } diff --git a/Content.Client/Graphics/Overlays/SingularityOverlay.cs b/Content.Client/Graphics/Overlays/SingularityOverlay.cs new file mode 100644 index 0000000000..624cfae2e8 --- /dev/null +++ b/Content.Client/Graphics/Overlays/SingularityOverlay.cs @@ -0,0 +1,174 @@ +#nullable enable +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using System.Collections.Generic; +using Robust.Client.Graphics; +using System.Linq; +using Robust.Shared.Enums; +using Robust.Shared.GameObjects; +using Content.Client.GameObjects.Components.Singularity; +using Robust.Shared.Map; + +namespace Content.Client.Graphics.Overlays +{ + public class SingularityOverlay : Overlay + { + [Dependency] private readonly IComponentManager _componentManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IClyde _displayManager = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpace; + public override bool RequestScreenTexture => true; + + private readonly ShaderInstance _shader; + + Dictionary _singularities = new Dictionary(); + + public SingularityOverlay() + { + IoCManager.InjectDependencies(this); + _shader = _prototypeManager.Index("Singularity").Instance().Duplicate(); + } + + public override bool OverwriteTargetFrameBuffer() + { + return _singularities.Count() > 0; + } + + protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) + { + SingularityQuery(); + + foreach (SingularityShaderInstance instance in _singularities.Values) + { + var tempCoords = _eyeManager.WorldToScreen(instance.CurrentMapCoords); + tempCoords.Y = _displayManager.ScreenSize.Y - tempCoords.Y; + _shader?.SetParameter("positionInput", tempCoords); + if (ScreenTexture != null) + _shader?.SetParameter("SCREEN_TEXTURE", ScreenTexture); + _shader?.SetParameter("intensity", LevelToIntensity(instance.Level)); + _shader?.SetParameter("falloff", LevelToFalloff(instance.Level)); + + handle.UseShader(_shader); + var worldHandle = (DrawingHandleWorld) handle; + var viewport = _eyeManager.GetWorldViewport(); + worldHandle.DrawRect(viewport, Color.White); + } + + } + + + + //Queries all singulos on the map and either adds or removes them from the list of singulos to render depending on their location and existence. + private float _maxDist = 15.0f; + private void SingularityQuery() + { + var currentEyeLoc = _eyeManager.CurrentEye.Position; + + var singuloComponents = _componentManager.EntityQuery(); + foreach (var singuloInterface in singuloComponents) + { + var singuloComponent = (Component)singuloInterface; + var singuloEntity = singuloComponent.Owner; + if (!_singularities.Keys.Contains(singuloEntity.Uid) && singuloEntity.Transform.Coordinates.InRange(_entityManager, EntityCoordinates.FromMap(_entityManager, singuloEntity.Transform.ParentUid, currentEyeLoc), _maxDist)) + { + _singularities.Add(singuloEntity.Uid, new SingularityShaderInstance(singuloEntity.Transform.MapPosition.Position, singuloInterface.Level)); + } + } + + var activeShaderUids = _singularities.Keys; + foreach (var activeSinguloUid in activeShaderUids) + { + if (_entityManager.TryGetEntity(activeSinguloUid, out IEntity? singuloEntity)) + { + if (!singuloEntity.Transform.Coordinates.InRange(_entityManager, EntityCoordinates.FromMap(_entityManager, singuloEntity.Transform.ParentUid, currentEyeLoc), _maxDist)) + { + _singularities.Remove(activeSinguloUid); + } + else + { + if (!singuloEntity.TryGetComponent(out var singuloInterface)) + { + _singularities.Remove(activeSinguloUid); + } + else + { + var shaderInstance = _singularities[activeSinguloUid]; + shaderInstance.CurrentMapCoords = singuloEntity.Transform.MapPosition.Position; + shaderInstance.Level = singuloInterface.Level; + } + } + + } + else + { + _singularities.Remove(activeSinguloUid); + } + } + + } + + + + + //I am lazy + private float LevelToIntensity(int level) + { + switch (level) + { + case 0: + return 0.0f; + case 1: + return 2.7f; + case 2: + return 14.4f; + case 3: + return 47.2f; + case 4: + return 180.0f; + case 5: + return 600.0f; + case 6: + return 800.0f; + + } + return -1.0f; + } + private float LevelToFalloff(int level) + { + switch (level) + { + case 0: + return 9999f; + case 1: + return 6.4f; + case 2: + return 7.0f; + case 3: + return 8.0f; + case 4: + return 10.0f; + case 5: + return 12.0f; + case 6: + return 12.0f; + } + return -1.0f; + } + + private sealed class SingularityShaderInstance + { + public Vector2 CurrentMapCoords; + public int Level; + public SingularityShaderInstance(Vector2 mapCoords, int level) + { + CurrentMapCoords = mapCoords; + Level = level; + } + } + } +} + diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index 70905418b4..4c3502512c 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -194,7 +194,6 @@ namespace Content.Client "ContainmentFieldGenerator", "ContainmentField", "Emitter", - "Singularity", "SingularityGenerator", "EmitterBoltComponent", "ParticleProjectile", diff --git a/Content.Client/Parallax/ParallaxOverlay.cs b/Content.Client/Parallax/ParallaxOverlay.cs index 71e93d5d3c..01d49e3bc7 100644 --- a/Content.Client/Parallax/ParallaxOverlay.cs +++ b/Content.Client/Parallax/ParallaxOverlay.cs @@ -1,5 +1,6 @@ -using Content.Client.Interfaces.Parallax; +using Content.Client.Interfaces.Parallax; using Robust.Client.Graphics; +using Robust.Shared.Enums; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -13,7 +14,6 @@ namespace Content.Client.Parallax [Dependency] private readonly IClyde _displayManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - public override bool AlwaysDirty => true; private const float Slowness = 0.5f; private Texture _parallaxTexture; @@ -21,7 +21,7 @@ namespace Content.Client.Parallax public override OverlaySpace Space => OverlaySpace.ScreenSpaceBelowWorld; private readonly ShaderInstance _shader; - public ParallaxOverlay() : base(nameof(ParallaxOverlay)) + public ParallaxOverlay() { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("unshaded").Instance(); diff --git a/Content.Client/StationEvents/RadiationPulseOverlay.cs b/Content.Client/StationEvents/RadiationPulseOverlay.cs index c78ca07311..ecb4905f6d 100644 --- a/Content.Client/StationEvents/RadiationPulseOverlay.cs +++ b/Content.Client/StationEvents/RadiationPulseOverlay.cs @@ -6,6 +6,7 @@ using Content.Client.GameObjects.Components.StationEvents; using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -44,7 +45,7 @@ namespace Content.Client.StationEvents // TODO: When worldHandle can do DrawCircle change this. public override OverlaySpace Space => OverlaySpace.ScreenSpace; - public RadiationPulseOverlay() : base(nameof(RadiationPulseOverlay)) + public RadiationPulseOverlay() { IoCManager.InjectDependencies(this); _lastTick = _gameTiming.CurTime; diff --git a/Content.Server/GameObjects/Components/PA/ParticleProjectileComponent.cs b/Content.Server/GameObjects/Components/PA/ParticleProjectileComponent.cs index 9f03ea0970..01578de9bd 100644 --- a/Content.Server/GameObjects/Components/PA/ParticleProjectileComponent.cs +++ b/Content.Server/GameObjects/Components/PA/ParticleProjectileComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.GameObjects.Components.Projectiles; +using Content.Server.GameObjects.Components.Projectiles; using Content.Server.GameObjects.Components.Singularity; using Content.Shared.GameObjects.Components; using Content.Shared.Physics; @@ -19,7 +19,7 @@ namespace Content.Server.GameObjects.Components.PA private ParticleAcceleratorPowerState _state; void IStartCollide.CollideWith(IPhysBody ourBody, IPhysBody otherBody, in Manifold manifold) { - if (otherBody.Entity.TryGetComponent(out var singularityComponent)) + if (otherBody.Entity.TryGetComponent(out var singularityComponent)) { var multiplier = _state switch { diff --git a/Content.Server/GameObjects/Components/Singularity/ContainmentFieldConnection.cs b/Content.Server/GameObjects/Components/Singularity/ContainmentFieldConnection.cs index a127bfa5bb..48a3286922 100644 --- a/Content.Server/GameObjects/Components/Singularity/ContainmentFieldConnection.cs +++ b/Content.Server/GameObjects/Components/Singularity/ContainmentFieldConnection.cs @@ -75,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Singularity public bool CanRepell(IEntity toRepell) { var powerNeeded = 1; - if (toRepell.TryGetComponent(out var singularityComponent)) + if (toRepell.TryGetComponent(out var singularityComponent)) { powerNeeded += 2*singularityComponent.Level; } diff --git a/Content.Server/GameObjects/Components/Singularity/SingularityComponent.cs b/Content.Server/GameObjects/Components/Singularity/ServerSingularityComponent.cs similarity index 88% rename from Content.Server/GameObjects/Components/Singularity/SingularityComponent.cs rename to Content.Server/GameObjects/Components/Singularity/ServerSingularityComponent.cs index 972c3bb3a1..1e16731abd 100644 --- a/Content.Server/GameObjects/Components/Singularity/SingularityComponent.cs +++ b/Content.Server/GameObjects/Components/Singularity/ServerSingularityComponent.cs @@ -1,34 +1,33 @@ #nullable enable +using Content.Server.GameObjects.Components.Observer; using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.StationEvents; -using Content.Server.GameObjects.Components.Observer; -using Content.Shared.GameObjects; using Content.Shared.Physics; -using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; -using Robust.Shared.Maths; using Robust.Shared.Map; +using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Physics.Collision; using Robust.Shared.Physics.Dynamics.Shapes; using Robust.Shared.Random; +using Robust.Server.GameObjects; +using Content.Shared.GameObjects.Components.Singularity; +using Robust.Shared.Players; using Robust.Shared.Timing; + namespace Content.Server.GameObjects.Components.Singularity { [RegisterComponent] - public class SingularityComponent : Component, IStartCollide + public class ServerSingularityComponent : SharedSingularityComponent, IStartCollide { [Dependency] private readonly IRobustRandom _random = default!; - public override uint? NetID => ContentNetIDs.SINGULARITY; - - public override string Name => "Singularity"; public int Energy { @@ -40,8 +39,6 @@ namespace Content.Server.GameObjects.Components.Singularity _energy = value; if (_energy <= 0) { - _spriteComponent?.LayerSetVisible(0, false); - Owner.Delete(); return; } @@ -76,10 +73,12 @@ namespace Content.Server.GameObjects.Components.Singularity _spriteComponent?.LayerSetRSI(0, "Constructible/Power/Singularity/singularity_" + _level + ".rsi"); _spriteComponent?.LayerSetState(0, "singularity_" + _level); - if(_collidableComponent != null && _collidableComponent.Fixtures.Any() && _collidableComponent.Fixtures[0].Shape is PhysShapeCircle circle) + if (_collidableComponent != null && _collidableComponent.Fixtures.Any() && _collidableComponent.Fixtures[0].Shape is PhysShapeCircle circle) { circle.Radius = _level - 0.5f; } + + Dirty(); } } private int _level; @@ -102,6 +101,11 @@ namespace Content.Server.GameObjects.Components.Singularity private AudioSystem _audioSystem = null!; private IPlayingAudioStream? _playingSound; + public override ComponentState GetComponentState(ICommonSession player) + { + return new SingularityComponentState(Level); + } + public override void Initialize() { base.Initialize(); @@ -114,26 +118,14 @@ namespace Content.Server.GameObjects.Components.Singularity _audioSystem.PlayFromEntity("/Audio/Effects/singularity_form.ogg", Owner); Timer.Spawn(5200,() => _playingSound = _audioSystem.PlayFromEntity("/Audio/Effects/singularity.ogg", Owner, audioParams)); - - if (!Owner.TryGetComponent(out _collidableComponent)) - { - Logger.Error("SingularityComponent was spawned without CollidableComponent"); - } - else - { - _collidableComponent.Hard = false; - } - if (!Owner.TryGetComponent(out _spriteComponent)) - { Logger.Error("SingularityComponent was spawned without SpriteComponent"); - } - if (!Owner.TryGetComponent(out _radiationPulseComponent)) - { Logger.Error("SingularityComponent was spawned without RadiationPulseComponent"); - } - + if (!Owner.TryGetComponent(out _collidableComponent)) + Logger.Error("SingularityComponent was spawned without CollidableComponent!"); + else + _collidableComponent.Hard = false; Level = 1; } @@ -161,7 +153,8 @@ namespace Content.Server.GameObjects.Components.Singularity return; } - if (otherEntity.IsInContainer()) return; + if (otherEntity.IsInContainer()) + return; otherEntity.Delete(); Energy++; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs index 5b0bf5a4c7..8197e4e488 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; @@ -115,12 +116,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee // TODO: Merge with the code in FlashableComponent private void Flash(IEntity entity, IEntity user, int flashDuration) { - if (entity.TryGetComponent(out FlashableComponent flashable)) + if (entity.TryGetComponent(out var flashable)) { flashable.Flash(flashDuration / 1000d); } - if (entity.TryGetComponent(out StunnableComponent stunnableComponent)) + if (entity.TryGetComponent(out var stunnableComponent)) { stunnableComponent.Slowdown(flashDuration / 1000f, _slowTo, _slowTo); } diff --git a/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs b/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs index bd29f6deff..9950fb9ff2 100644 --- a/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs @@ -7,23 +7,24 @@ namespace Content.Server.GameObjects.EntitySystems [UsedImplicitly] public class SingularitySystem : EntitySystem { + private float _updateInterval = 1.0f; private float _accumulator; public override void Update(float frameTime) { base.Update(frameTime); - _accumulator += frameTime; - while (_accumulator > 1.0f) + while (_accumulator > _updateInterval) { - _accumulator -= 1.0f; + _accumulator -= _updateInterval; - foreach (var singularity in ComponentManager.EntityQuery()) + foreach (var singularity in ComponentManager.EntityQuery()) { singularity.Update(1); } } + } } } diff --git a/Content.Server/IgnoredComponents.cs b/Content.Server/IgnoredComponents.cs index 9003823e8c..86f6d25498 100644 --- a/Content.Server/IgnoredComponents.cs +++ b/Content.Server/IgnoredComponents.cs @@ -18,6 +18,7 @@ namespace Content.Server "RadiatingLight", "Icon", "ClientEntitySpawner", + "ToySingularity" }; } } diff --git a/Content.Server/Physics/Controllers/SingularityController.cs b/Content.Server/Physics/Controllers/SingularityController.cs index 9a0a6a1b86..7702bcd04d 100644 --- a/Content.Server/Physics/Controllers/SingularityController.cs +++ b/Content.Server/Physics/Controllers/SingularityController.cs @@ -32,7 +32,7 @@ namespace Content.Server.Physics.Controllers { _pullAccumulator -= 0.5f; - foreach (var singularity in ComponentManager.EntityQuery()) + foreach (var singularity in ComponentManager.EntityQuery()) { // TODO: Use colliders instead probably yada yada PullEntities(singularity); @@ -45,7 +45,7 @@ namespace Content.Server.Physics.Controllers { _moveAccumulator -= 1.0f; - foreach (var (singularity, physics) in ComponentManager.EntityQuery()) + foreach (var (singularity, physics) in ComponentManager.EntityQuery()) { if (singularity.Owner.HasComponent()) continue; @@ -57,7 +57,7 @@ namespace Content.Server.Physics.Controllers } } - private void MoveSingulo(SingularityComponent singularity, PhysicsComponent physics) + private void MoveSingulo(ServerSingularityComponent singularity, PhysicsComponent physics) { if (singularity.Level <= 1) return; // TODO: Could try gradual changes instead but for now just try to replicate @@ -70,7 +70,7 @@ namespace Content.Server.Physics.Controllers physics.LinearVelocity = pushVector.Normalized * 2; } - private void PullEntities(SingularityComponent component) + private void PullEntities(ServerSingularityComponent component) { var singularityCoords = component.Owner.Transform.Coordinates; // TODO: Maybe if we have named fixtures needs to pull out the outer circle collider (inner will be for deleting). @@ -89,7 +89,7 @@ namespace Content.Server.Physics.Controllers } } - private void DestroyTiles(SingularityComponent component) + private void DestroyTiles(ServerSingularityComponent component) { if (!component.Owner.TryGetComponent(out PhysicsComponent? physicsComponent)) return; var worldBox = physicsComponent.GetWorldAABB(); diff --git a/Content.Shared/GameObjects/Components/Singularity/SharedSingularityComponent.cs b/Content.Shared/GameObjects/Components/Singularity/SharedSingularityComponent.cs new file mode 100644 index 0000000000..0d16c407b0 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Singularity/SharedSingularityComponent.cs @@ -0,0 +1,25 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using System; + +namespace Content.Shared.GameObjects.Components.Singularity +{ + + public abstract class SharedSingularityComponent : Component + { + public override string Name => "Singularity"; + public override uint? NetID => ContentNetIDs.SINGULARITY; + + + [Serializable, NetSerializable] + protected sealed class SingularityComponentState : ComponentState + { + public int Level { get; } + + public SingularityComponentState(int level) : base(ContentNetIDs.SINGULARITY) + { + Level = level; + } + } + } +} diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 5353525ba6..acb6cf47b0 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -4,7 +4,7 @@ name: bee plushie parent: BaseItem id: PlushieBee - description: A cute toy that resembles an even cuter coder. + description: A cute toy that resembles an even cuter programmer. components: - type: Toys - type: LoopingSound @@ -49,7 +49,7 @@ name: nar'sie plushie parent: BaseItem id: PlushieNar - description: A small stuffed doll of the elder goddess Nar'Sie. Who thought this was a good children's toy? + description: A small stuffed doll of the elder goddess Nar'Sie. components: - type: Toys - type: LoopingSound @@ -64,7 +64,7 @@ name: carp plushie parent: BaseItem id: PlushieCarp - description: An adorable stuffed toy that resembles a space carp. + description: An adorable stuffed toy that resembles the monstrous space carp. components: - type: Toys - type: LoopingSound @@ -97,7 +97,7 @@ name: snake plushie parent: BaseItem id: PlushieSnake - description: An adorable stuffed toy that resembles a snake. Not to be mistaken for the real thing. + description: An adorable stuffed toy that resembles a snake. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -129,7 +129,7 @@ name: help me carving parent: BaseItem id: CarvingHelpMe - description: Help me... + description: Help me! components: - type: Sprite sprite: Objects/Misc/carvings.rsi @@ -191,7 +191,7 @@ name: very good carving parent: BaseItem id: CarvingVeryGood - description: Very Good! + description: Very good! components: - type: Sprite sprite: Objects/Misc/carvings.rsi @@ -211,7 +211,7 @@ name: sorry carving parent: BaseItem id: CarvingImSorry - description: I'm sorry... + description: I'm sorry. components: - type: Sprite sprite: Objects/Misc/carvings.rsi @@ -233,7 +233,7 @@ name: AI toy parent: BaseItem id: ToyAi - description: A little toy model AI core. + description: A scaled-down toy AI core. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -243,7 +243,7 @@ name: nuke toy parent: BaseItem id: ToyNuke - description: A plastic model of a Nuclear Fission Explosive. What child plays with this? + description: A plastic model of a Nuclear Fission Explosive. No uranium included... probably. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -276,7 +276,7 @@ name: h.o.n.k. toy parent: BaseItem id: ToyHonk - description: Mini-Mecha action figure! Collect them all! 6/12. + description: Mini-Mecha action figure! 'Mecha No. 6/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -286,7 +286,7 @@ name: ian toy parent: BaseItem id: ToyIan - description: Ian action figure. + description: Unable to eat, but just as fluffy as the real guy! components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -302,7 +302,7 @@ name: marauder toy parent: BaseItem id: ToyMarauder - description: Mini-Mecha action figure! Collect them all! 7/12. + description: Mini-Mecha action figure! 'Mecha No. 7/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -312,7 +312,7 @@ name: mauler toy parent: BaseItem id: ToyMauler - description: Mini-Mecha action figure! Collect them all! 9/12. + description: Mini-Mecha action figure! 'Mecha No. 9/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -322,7 +322,7 @@ name: gygax toy parent: BaseItem id: ToyGygax - description: Mini-Mecha action figure! Collect them all! 4/12. + description: Mini-Mecha action figure! 'Mecha No. 4/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -332,7 +332,7 @@ name: odysseus toy parent: BaseItem id: ToyOdysseus - description: Mini-Mecha action figure! Collect them all! 10/12. + description: Mini-Mecha action figure! 'Mecha No. 10/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -352,7 +352,7 @@ name: deathripley toy parent: BaseItem id: ToyDeathRipley - description: Mini-Mecha action figure! Collect them all! 3/12. + description: Mini-Mecha action figure! 'Mecha No. 3/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -362,7 +362,7 @@ name: phazon toy parent: BaseItem id: ToyPhazon - description: Mini-Mecha action figure! Collect them all! 11/12. + description: Mini-Mecha action figure! 'Mecha No. 11/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -372,7 +372,7 @@ name: fire ripley parent: BaseItem id: ToyFireRipley - description: Mini-Mecha action figure! Collect them all! 2/12. + description: Mini-Mecha action figure! 'Mecha No. 2/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -382,7 +382,7 @@ name: reticence toy parent: BaseItem id: ToyReticence - description: Mini-Mecha action figure! Collect them all! 12/12. + description: Mini-Mecha action figure! 'Mecha No. 12/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -392,7 +392,7 @@ name: ripley toy parent: BaseItem id: ToyRipley - description: Mini-Mecha action figure! Collect them all! 1/12. + description: Mini-Mecha action figure! 'Mecha No. 1/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -403,7 +403,7 @@ name: seraph toy parent: BaseItem id: ToySeraph - description: Mini-Mecha action figure! Collect them all! 8/12. + description: Mini-Mecha action figure! 'Mecha No. 8/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -414,7 +414,7 @@ name: durand toy parent: BaseItem id: ToyDurand - description: Mini-Mecha action figure! Collect them all! 5/12. + description: Mini-Mecha action figure! 'Mecha No. 5/12' is written on the back. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -427,7 +427,7 @@ name: skeleton toy parent: BaseItem id: ToySkeleton - description: Spooked yah! + description: Spooked ya! components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -567,7 +567,7 @@ name: football parent: BaseItem id: Football - description: Go Sports Go! + description: Otherwise known as a handegg. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -583,7 +583,7 @@ name: syndie balloon parent: BaseItem id: BalloonSyn - description: Loud and proud. + description: Handed out to the bravest souls who survived the "atomic twister" ride at Syndieland. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -598,7 +598,7 @@ name: corgi balloon parent: BaseItem id: BalloonCorgi - description: Cute. + description: Just like owning a real dog - but a lot floatier. components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -608,3 +608,22 @@ size: 24 sprite: Objects/Fun/toys.rsi HeldPrefix: corgib + +- type: entity + name: singuloth-brand toy + parent: BaseItem + id: SingularityToy + description: Mass-produced by a sadistic corporate conglomerate! + components: + - type: Sprite + sprite: Objects/Fun/toys.rsi + state: singularitytoy + - type: Icon + sprite: Objects/Fun/toys.rsi + state: singularitytoy + - type: ToySingularity + + - type: Item + size: 12 + sprite: Objects/Fun/toys.rsi + HeldPrefix: singularitytoy \ No newline at end of file diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml index b02acfe811..0c0919abe7 100644 --- a/Resources/Prototypes/Shaders/shaders.yml +++ b/Resources/Prototypes/Shaders/shaders.yml @@ -7,8 +7,23 @@ id: GradientCircleMask kind: source path: "/Textures/Shaders/gradient_circle_mask.swsl" + +- type: shader + id: ColoredScreenBorder + kind: source + path: "/Textures/Shaders/colored_screen_border.swsl" - type: shader id: FlashedEffect kind: source path: "/Textures/Shaders/flashed_effect.swsl" + +- type: shader + id: Singularity + kind: source + path: "/Textures/Shaders/singularity.swsl" + +- type: shader + id: Texture + kind: source + path: "/Textures/Shaders/texture.swsl" diff --git a/Resources/Textures/Objects/Fun/toys.rsi/meta.json b/Resources/Textures/Objects/Fun/toys.rsi/meta.json index 25b565901c..140656e79e 100644 --- a/Resources/Textures/Objects/Fun/toys.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/toys.rsi/meta.json @@ -261,6 +261,22 @@ 0.1 ] ] + }, + { + "name": "singularitytoy", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Fun/toys.rsi/singularitytoy.png b/Resources/Textures/Objects/Fun/toys.rsi/singularitytoy.png new file mode 100644 index 0000000000..b609db734f Binary files /dev/null and b/Resources/Textures/Objects/Fun/toys.rsi/singularitytoy.png differ diff --git a/Resources/Textures/Shaders/colored_screen_border.swsl b/Resources/Textures/Shaders/colored_screen_border.swsl new file mode 100644 index 0000000000..e1c57f01a2 --- /dev/null +++ b/Resources/Textures/Shaders/colored_screen_border.swsl @@ -0,0 +1,21 @@ +//Creates a border on the edges of the screen of the specified color and of the specified size (no uniforms yet cause I'm lazy) + +const highp vec4 borderColor = vec4(230.0, 0.0, 0.0, 1.0); +const highp float borderSize = 30; //Pixel size of border + +void fragment() { + highp vec2 pixelSize = vec2(1.0/SCREEN_PIXEL_SIZE.x, 1.0/SCREEN_PIXEL_SIZE.y); + highp float smallestLength = FRAGCOORD.x; + if(smallestLength > FRAGCOORD.y){ + smallestLength = FRAGCOORD.y; + } + if(smallestLength > pixelSize.x-FRAGCOORD.x){ + smallestLength = pixelSize.x-FRAGCOORD.x; + } + if(smallestLength > pixelSize.y-FRAGCOORD.y){ + smallestLength = pixelSize.y-FRAGCOORD.y; + } + if(smallestLength <= borderSize){ + COLOR = vec4(borderColor.r, borderColor.g, borderColor.b, abs((1.0-(smallestLength/borderSize))*(abs(sin(TIME))*0.8+0.2))); + } +} \ No newline at end of file diff --git a/Resources/Textures/Shaders/gradient_circle_mask.swsl b/Resources/Textures/Shaders/gradient_circle_mask.swsl index f32fa4ce5f..a00a9d2d48 100644 --- a/Resources/Textures/Shaders/gradient_circle_mask.swsl +++ b/Resources/Textures/Shaders/gradient_circle_mask.swsl @@ -1,25 +1,25 @@ +//This shader defines two circles - everything inside the inner circle will be darkened, while everything outside the outer circle +//will be full black. Between the inner and outer circle it LERPs from the inner darkness to full black. + light_mode unshaded; -const highp float percentagedistanceshow = 0.05; -const highp float gradientfalloffwidth = 3.0; - -highp vec4 circle(in highp vec2 uv, in highp vec2 pos, highp float rad, in highp vec3 color) { - highp float d = length(pos - uv) - rad; - highp float t = clamp(d, 0.0, 1.0); - return vec4(color, t); -} +const highp float darknessAlphaInner = 0.6; +const highp float innerCircleRadius = 40; //Note: this is in pixels +const highp float outerCircleRadius = 80; void fragment() { - highp vec2 uv = FRAGCOORD.xy; - highp vec2 res_xy = vec2(1.0/SCREEN_PIXEL_SIZE.x, 1.0/SCREEN_PIXEL_SIZE.y); - highp vec2 center = res_xy*0.5; - highp float radius = percentagedistanceshow * res_xy.y; - - highp vec4 grad = vec4(0.8 - length( uv - center )/res_xy.y * gradientfalloffwidth); - - highp vec4 layer1 = vec4(vec3(255.0),0.0); - - highp vec4 layer2 = circle(uv, center, radius, grad.rgb); - - COLOR = mix(layer1, layer2, layer2.a); + highp vec2 pixelSize = vec2(1.0/SCREEN_PIXEL_SIZE.x, 1.0/SCREEN_PIXEL_SIZE.y); + highp vec2 pixelCenter = pixelSize*0.5; + highp float distance = length(FRAGCOORD.xy - pixelCenter); + if(distance > outerCircleRadius){ + COLOR = vec4(0.0, 0.0, 0.0, 1.0); + } + else if(distance < innerCircleRadius){ + COLOR = vec4(0.0, 0.0, 0.0, darknessAlphaInner); + } + else{ + highp float intensity = (distance-innerCircleRadius)/(outerCircleRadius-innerCircleRadius); + COLOR = vec4(0.0, 0.0, 0.0, (1-intensity)*darknessAlphaInner + intensity); + } } + diff --git a/Resources/Textures/Shaders/singularity.swsl b/Resources/Textures/Shaders/singularity.swsl new file mode 100644 index 0000000000..046df1afd0 --- /dev/null +++ b/Resources/Textures/Shaders/singularity.swsl @@ -0,0 +1,32 @@ +//Gravitational lensing effect. Edited from https://unionassets.com/blog/the-effect-of-the-gravitational-lens-195 to be Clyde based (based on what) + +uniform sampler2D SCREEN_TEXTURE; +uniform highp vec2 positionInput = vec2(0,0); +uniform highp float falloff = 5.0; +uniform highp float intensity = 5.0; + + + +void fragment() { + float distanceToCenter = length(FRAGCOORD.xy-positionInput); + + vec2 finalCoords = FRAGCOORD.xy - positionInput; + highp float deformation = (pow(intensity, 2)*500) / pow(distanceToCenter, pow(falloff, 0.5)); + if(deformation > 0.8) //Edit this for inward effect + deformation = pow(deformation, 0.3); + if(deformation > 0.001){ + finalCoords *= 1-deformation; //Change this to 1+deformation for inward effect + finalCoords += positionInput; + //float darkenCircleSize = 600; //Calculate optional darkening effect (darker the closer we are to the center of the singularity) + //float alph = (distanceToCenter-30)/(darkenCircleSize-30); + //float darkening = 0.9-(alph*0.9); + + //Darkening effect optional (Darker the closer you are to the center) + //COLOR = mix(texture(SCREEN_TEXTURE, finalCoords*SCREEN_PIXEL_SIZE), vec4(0.0, 0.0, 0.0, 1.0), darkening); + COLOR = texture(SCREEN_TEXTURE, finalCoords*SCREEN_PIXEL_SIZE); + } + else{ + COLOR = texture(SCREEN_TEXTURE, FRAGCOORD.xy*SCREEN_PIXEL_SIZE); + } + +} \ No newline at end of file diff --git a/Resources/Textures/Shaders/texture.swsl b/Resources/Textures/Shaders/texture.swsl new file mode 100644 index 0000000000..f92733058f --- /dev/null +++ b/Resources/Textures/Shaders/texture.swsl @@ -0,0 +1,23 @@ + +//Draws the given texture at the given screen coords. Useful in specific scenarios (i.e. this was made for drawing singularity sprites over the lensing effect but below FOV) +//Currently does not work with AtlasTextures, going to need some work. + +uniform sampler2D tex; +uniform highp vec2 positionInput = vec2(0,0); +uniform highp vec2 pixelSize = vec2(32, 32); +uniform highp float alphaCutoff = 0.0; +uniform bool removeTransparency = false; + +void fragment() { + float pixelLength = pixelSize.x*2; + float halvedLength = pixelLength/2; + if(FRAGCOORD.x > positionInput.x - halvedLength && FRAGCOORD.x < positionInput.x + halvedLength && FRAGCOORD.y > positionInput.y - halvedLength && FRAGCOORD.y < positionInput.y + halvedLength){ + vec2 finalCoords = (FRAGCOORD.xy-positionInput+(pixelLength/2))/pixelLength; + vec4 color = texture(tex, finalCoords); + if(color.a > alphaCutoff){ + if(removeTransparency) + color.a = 1.0; + COLOR = color; + } + } +} \ No newline at end of file diff --git a/RobustToolbox b/RobustToolbox index 4bc775c01c..a0d241e551 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 4bc775c01c1019686c8b3f42c571f1040765f69f +Subproject commit a0d241e551404cec586df5a7e1fe9ef3b5ec3eeb