diff --git a/Content.Client/Beam/BeamSystem.cs b/Content.Client/Beam/BeamSystem.cs new file mode 100644 index 0000000000..c221e79769 --- /dev/null +++ b/Content.Client/Beam/BeamSystem.cs @@ -0,0 +1,31 @@ +using Content.Client.Beam.Components; +using Content.Shared.Beam; +using Content.Shared.Beam.Components; +using Robust.Client.GameObjects; + +namespace Content.Client.Beam; + +public sealed class BeamSystem : SharedBeamSystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(BeamVisualizerMessage); + } + + //TODO: Sometime in the future this needs to be replaced with tiled sprites + private void BeamVisualizerMessage(BeamVisualizerEvent args) + { + if (TryComp(args.Beam, out var sprites)) + { + sprites.Rotation = args.UserAngle; + + if (args.BodyState != null) + { + sprites.LayerSetState(0, args.BodyState); + sprites.LayerSetShader(0, args.Shader); + } + } + } +} diff --git a/Content.Client/Beam/Components/BeamComponent.cs b/Content.Client/Beam/Components/BeamComponent.cs new file mode 100644 index 0000000000..eb10d32f53 --- /dev/null +++ b/Content.Client/Beam/Components/BeamComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Beam.Components; + +namespace Content.Client.Beam.Components; +[RegisterComponent] +public sealed class BeamComponent : SharedBeamComponent +{ + +} diff --git a/Content.Client/Lightning/Components/LightningComponent.cs b/Content.Client/Lightning/Components/LightningComponent.cs new file mode 100644 index 0000000000..4edc97597f --- /dev/null +++ b/Content.Client/Lightning/Components/LightningComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Lightning.Components; + +namespace Content.Client.Lightning.Components; +[RegisterComponent] +public sealed class LightningComponent : SharedLightningComponent +{ + +} diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index a59d38fe46..5fe857dcf5 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; +using Robust.Shared.Physics; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Markdown; @@ -232,7 +233,7 @@ public sealed class PrototypeSaveTest var compName = compFact.GetComponentName(compType); compNames.Add(compName); - if (compType == typeof(MetaDataComponent) || compType == typeof(TransformComponent)) + if (compType == typeof(MetaDataComponent) || compType == typeof(TransformComponent) || compType == typeof(FixturesComponent)) continue; MappingDataNode compMapping; diff --git a/Content.Server/Beam/BeamSystem.cs b/Content.Server/Beam/BeamSystem.cs new file mode 100644 index 0000000000..73d44a24d4 --- /dev/null +++ b/Content.Server/Beam/BeamSystem.cs @@ -0,0 +1,172 @@ +using Content.Server.Beam.Components; +using Content.Server.Lightning; +using Content.Shared.Beam; +using Content.Shared.Beam.Components; +using Content.Shared.Interaction; +using Content.Shared.Lightning; +using Content.Shared.Physics; +using Robust.Server.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Collision.Shapes; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Dynamics; +using Robust.Shared.Physics.Systems; + +namespace Content.Server.Beam; + +public sealed class BeamSystem : SharedBeamSystem +{ + [Dependency] private readonly FixtureSystem _fixture = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnBeamCreationSuccess); + SubscribeLocalEvent(OnControllerCreated); + SubscribeLocalEvent(OnBeamFired); + SubscribeLocalEvent(OnRemove); + } + + private void OnBeamCreationSuccess(EntityUid uid, BeamComponent component, CreateBeamSuccessEvent args) + { + component.BeamShooter = args.User; + } + + private void OnControllerCreated(EntityUid uid, BeamComponent component, BeamControllerCreatedEvent args) + { + component.OriginBeam = args.OriginBeam; + } + + private void OnBeamFired(EntityUid uid, BeamComponent component, BeamFiredEvent args) + { + component.CreatedBeams.Add(args.CreatedBeam); + } + + private void OnRemove(EntityUid uid, BeamComponent component, ComponentRemove args) + { + if (component.VirtualBeamController == null) + return; + + if (component.CreatedBeams.Count == 0 && component.VirtualBeamController.Value.Valid) + QueueDel(component.VirtualBeamController.Value); + } + + /// + /// If is successful, it spawns a beam from the user to the target. + /// + /// The prototype used to make the beam + /// Angle of the user firing the beam + /// The calculated distance from the user to the target. + /// Where the beam will spawn in + /// Calculated correction so the can be properly dynamically created + /// The virtual beam controller that this beam will use. If one doesn't exist it will be created here. + /// Optional sprite state for the if it needs a dynamic one + /// Optional shader for the and if it needs something other than default + private void CreateBeam(string prototype, + Angle userAngle, + Vector2 calculatedDistance, + MapCoordinates beamStartPos, + Vector2 distanceCorrection, + EntityUid? controller, + string? bodyState = null, + string shader = "unshaded") + { + var beamSpawnPos = beamStartPos; + var ent = Spawn(prototype, beamSpawnPos); + var shape = new EdgeShape(distanceCorrection, new Vector2(0,0)); + var distanceLength = distanceCorrection.Length; + + if (TryComp(ent, out var physics) && TryComp(ent, out var beam)) + { + var fixture = new Fixture(physics, shape) + { + ID = "BeamBody", + Hard = false, + CollisionMask = (int)CollisionGroup.ItemMask, //Change to MobMask + CollisionLayer = (int)CollisionGroup.MobLayer //Change to WallLayer + }; + + _fixture.TryCreateFixture(physics, fixture); + physics.BodyType = BodyType.Dynamic; + + var beamVisualizerEvent = new BeamVisualizerEvent(ent, distanceLength, userAngle, bodyState, shader); + RaiseNetworkEvent(beamVisualizerEvent); + + if (controller != null) + beam.VirtualBeamController = controller; + + else + { + var controllerEnt = Spawn("VirtualBeamEntityController", beamSpawnPos); + beam.VirtualBeamController = controllerEnt; + + _audio.PlayPvs(beam.Sound, beam.Owner); + + var beamControllerCreatedEvent = new BeamControllerCreatedEvent(ent, controllerEnt); + RaiseLocalEvent(controllerEnt, beamControllerCreatedEvent); + } + + //Create the rest of the beam, sprites handled through the BeamVisualizerEvent + for (int i = 0; i < distanceLength-1; i++) + { + beamSpawnPos = beamSpawnPos.Offset(calculatedDistance.Normalized); + var newEnt = Spawn(prototype, beamSpawnPos); + + var ev = new BeamVisualizerEvent(newEnt, distanceLength, userAngle, bodyState, shader); + RaiseNetworkEvent(ev); + } + + var beamFiredEvent = new BeamFiredEvent(ent); + RaiseLocalEvent(beam.VirtualBeamController.Value, beamFiredEvent); + } + } + + /// + /// Called where you want an entity to create a beam from one target to another. + /// Tries to create the beam and does calculations like the distance, angle, and offset. + /// + /// The entity that's firing off the beam + /// The entity that's being targeted by the user + /// The prototype spawned when this beam is created + /// Optional sprite state for the if a default one is not given + /// Optional shader for the if a default one is not given + /// + public void TryCreateBeam(EntityUid user, EntityUid target, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null) + { + if (!user.IsValid() || !target.IsValid()) + return; + + var userMapPos = Transform(user).MapPosition; + var targetMapPos = Transform(target).MapPosition; + + //The distance between the target and the user. + var calculatedDistance = targetMapPos.Position - userMapPos.Position; + var userAngle = calculatedDistance.ToWorldAngle(); + + if (userMapPos.MapId != targetMapPos.MapId) + return; + + //Where the start of the beam will spawn + var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized); + + //Don't divide by zero + if (calculatedDistance.Length == 0) + return; + + if (controller != null && TryComp(controller, out var controllerBeamComp)) + { + controllerBeamComp.HitTargets.Add(user); + controllerBeamComp.HitTargets.Add(target); + } + + var distanceCorrection = calculatedDistance - calculatedDistance.Normalized; + + CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader); + + var ev = new CreateBeamSuccessEvent(user, target); + RaiseLocalEvent(user, ev); + } +} diff --git a/Content.Server/Beam/Components/BeamComponent.cs b/Content.Server/Beam/Components/BeamComponent.cs new file mode 100644 index 0000000000..960b59f9a4 --- /dev/null +++ b/Content.Server/Beam/Components/BeamComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Beam.Components; + +namespace Content.Server.Beam.Components; +[RegisterComponent] +public sealed class BeamComponent : SharedBeamComponent +{ + +} diff --git a/Content.Server/Lightning/Components/LightningComponent.cs b/Content.Server/Lightning/Components/LightningComponent.cs new file mode 100644 index 0000000000..598d4112a5 --- /dev/null +++ b/Content.Server/Lightning/Components/LightningComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Lightning.Components; + +namespace Content.Server.Lightning.Components; +[RegisterComponent] +public sealed class LightningComponent : SharedLightningComponent +{ + +} diff --git a/Content.Server/Lightning/LightningSystem.cs b/Content.Server/Lightning/LightningSystem.cs new file mode 100644 index 0000000000..523cf734ab --- /dev/null +++ b/Content.Server/Lightning/LightningSystem.cs @@ -0,0 +1,138 @@ +using System.Linq; +using Content.Server.Beam; +using Content.Server.Beam.Components; +using Content.Server.Lightning.Components; +using Content.Shared.Lightning; +using Robust.Server.GameObjects; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Dynamics; +using Robust.Shared.Physics.Events; +using Robust.Shared.Random; + +namespace Content.Server.Lightning; + +public sealed class LightningSystem : SharedLightningSystem +{ + [Dependency] private readonly PhysicsSystem _physics = default!; + [Dependency] private readonly BeamSystem _beam = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnCollide); + SubscribeLocalEvent(OnRemove); + } + + private void OnRemove(EntityUid uid, LightningComponent component, ComponentRemove args) + { + if (!TryComp(uid, out var lightningBeam) || !TryComp(lightningBeam.VirtualBeamController, out var beamController)) + { + return; + } + + beamController.CreatedBeams.Remove(uid); + } + + private void OnCollide(EntityUid uid, LightningComponent component, ref StartCollideEvent args) + { + if (!TryComp(uid, out var lightningBeam) || !TryComp(lightningBeam.VirtualBeamController, out var beamController)) + { + return; + } + + if (component.CanArc) + { + while (beamController.CreatedBeams.Count < component.MaxTotalArcs) + { + Arc(component, args.OtherFixture.Body.Owner, lightningBeam.VirtualBeamController.Value); + + var spriteState = LightningRandomizer(); + + component.ArcTargets.Add(args.OtherFixture.Body.Owner); + component.ArcTargets.Add(component.ArcTarget); + + _beam.TryCreateBeam(args.OtherFixture.Body.Owner, component.ArcTarget, component.LightningPrototype, spriteState, controller: lightningBeam.VirtualBeamController.Value); + + //Break from this loop so other created bolts can collide and arc + break; + } + } + } + + /// + /// Fires lightning from user to target + /// + /// Where the lightning fires from + /// Where the lightning fires to + /// The prototype for the lightning to be created + public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning") + { + var spriteState = LightningRandomizer(); + _beam.TryCreateBeam(user, target, lightningPrototype, spriteState); + } + + /// + /// Looks for a target to arc to in all 8 directions, adds the closest to a local dictionary and picks at random + /// + /// + /// + /// + private void Arc(LightningComponent component, EntityUid target, EntityUid controllerEntity) + { + if (!TryComp(controllerEntity, out var controller)) + return; + + var targetXForm = Transform(target); + var directions = Enum.GetValues().Length; + + var lightningQuery = GetEntityQuery(); + var beamQuery = GetEntityQuery(); + var xformQuery = GetEntityQuery(); + + Dictionary arcDirections = new(); + + //TODO: Add scoring system for the Tesla PR which will have grounding rods + for (int i = 0; i < directions; i++) + { + var direction = (Direction) i; + var (targetPos, targetRot) = targetXForm.GetWorldPositionRotation(xformQuery); + var dirRad = direction.ToAngle() + targetRot; + var ray = new CollisionRay(targetPos, dirRad.ToVec(), component.CollisionMask); + var rayCastResults = _physics.IntersectRay(targetXForm.MapID, ray, component.MaxLength, target, false).ToList(); + + RayCastResults? closestResult = null; + + foreach (var result in rayCastResults) + { + if (lightningQuery.HasComponent(result.HitEntity) + || beamQuery.HasComponent(result.HitEntity) + || component.ArcTargets.Contains(result.HitEntity) + || controller.HitTargets.Contains(result.HitEntity) + || controller.BeamShooter == result.HitEntity) + { + continue; + } + + closestResult = result; + break; + } + + if (closestResult == null) + { + continue; + } + + arcDirections.Add(direction, closestResult.Value.HitEntity); + } + + var randomDirection = (Direction) _random.Next(0, 7); + + if (arcDirections.ContainsKey(randomDirection)) + { + component.ArcTarget = arcDirections.GetValueOrDefault(randomDirection); + arcDirections.Clear(); + } + } +} diff --git a/Content.Shared/Beam/Components/SharedBeamComponent.cs b/Content.Shared/Beam/Components/SharedBeamComponent.cs new file mode 100644 index 0000000000..f5935447fd --- /dev/null +++ b/Content.Shared/Beam/Components/SharedBeamComponent.cs @@ -0,0 +1,120 @@ +using Robust.Shared.Audio; +using Robust.Shared.Map; +using Robust.Shared.Serialization; + +namespace Content.Shared.Beam.Components; +/// +/// Use this as a generic beam. Not for something like a laser gun, more for something continuous like lightning. +/// +public abstract class SharedBeamComponent : Component +{ + /// + /// A unique list of targets that this beam collided with. + /// Useful for code like Arcing in the Lightning Component. + /// + [ViewVariables] + [DataField("hitTargets")] + public HashSet HitTargets = new(); + + /// + /// The virtual entity representing a beam. + /// + [ViewVariables] + [DataField("virtualBeamController")] + public EntityUid? VirtualBeamController; + + /// + /// The first beam created, useful for keeping track of chains. + /// + [ViewVariables] + [DataField("originBeam")] + public EntityUid OriginBeam; + + /// + /// The entity that fired the beam originally + /// + [ViewVariables] + [DataField("beamShooter")] + public EntityUid BeamShooter; + + /// + /// A unique list of created beams that the controller keeps track of. + /// + [ViewVariables] + [DataField("createdBeams")] + public HashSet CreatedBeams = new(); + + /// + /// Sound played upon creation + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("sound")] + public SoundSpecifier? Sound; +} + +/// +/// Called where a is first created. Stores the originator beam euid and the controller euid. +/// Raised on the and broadcast. +/// +public sealed class BeamControllerCreatedEvent : EntityEventArgs +{ + public EntityUid OriginBeam; + public EntityUid BeamControllerEntity; + + public BeamControllerCreatedEvent(EntityUid originBeam, EntityUid beamControllerEntity) + { + OriginBeam = originBeam; + BeamControllerEntity = beamControllerEntity; + } +} + +/// +/// Called after TryCreateBeam succeeds. +/// +public sealed class CreateBeamSuccessEvent : EntityEventArgs +{ + public readonly EntityUid User; + public readonly EntityUid Target; + + public CreateBeamSuccessEvent(EntityUid user, EntityUid target) + { + User = user; + Target = target; + } +} + +/// +/// Called once the beam is fully created +/// +public sealed class BeamFiredEvent : EntityEventArgs +{ + public readonly EntityUid CreatedBeam; + + public BeamFiredEvent(EntityUid createdBeam) + { + CreatedBeam = createdBeam; + } +} + +/// +/// Raised on the new entity created after the creates one. +/// Used to get sprite data over to the client. +/// +[Serializable, NetSerializable] +public sealed class BeamVisualizerEvent : EntityEventArgs +{ + public readonly EntityUid Beam; + public readonly float DistanceLength; + public readonly Angle UserAngle; + public readonly string? BodyState; + public readonly string Shader = "unshaded"; + + public BeamVisualizerEvent(EntityUid beam, float distanceLength, Angle userAngle, string? bodyState = null, string shader = "unshaded") + { + Beam = beam; + DistanceLength = distanceLength; + UserAngle = userAngle; + BodyState = bodyState; + Shader = shader; + } +} diff --git a/Content.Shared/Beam/SharedBeamSystem.cs b/Content.Shared/Beam/SharedBeamSystem.cs new file mode 100644 index 0000000000..1127982cbb --- /dev/null +++ b/Content.Shared/Beam/SharedBeamSystem.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.Beam; + +public abstract class SharedBeamSystem : EntitySystem +{ + +} diff --git a/Content.Shared/Lightning/Components/SharedLightningComponent.cs b/Content.Shared/Lightning/Components/SharedLightningComponent.cs new file mode 100644 index 0000000000..243a97ed04 --- /dev/null +++ b/Content.Shared/Lightning/Components/SharedLightningComponent.cs @@ -0,0 +1,60 @@ +using Content.Shared.Physics; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Lightning.Components; +/// +/// Handles how lightning acts and is spawned. Use the ShootLightning method to fire lightning from one user to a target. +/// +public abstract class SharedLightningComponent : Component +{ + /// + /// Can this lightning arc? + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("canArc")] + public bool CanArc; + + /// + /// How much should lightning arc in total? + /// Controls the amount of bolts that will spawn. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("maxTotalArc")] + public int MaxTotalArcs = 50; + + /// + /// The prototype ID used for arcing bolts. Usually will be the same name as the main proto but it could be flexible. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("lightningPrototype", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string LightningPrototype = "Lightning"; + + /// + /// The target that the lightning will Arc to. + /// + [ViewVariables] + [DataField("arcTarget")] + public EntityUid ArcTarget; + + /// + /// How far should this lightning go? + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("maxLength")] + public float MaxLength = 5f; + + /// + /// List of targets that this collided with already + /// + [ViewVariables] + [DataField("arcTargets")] + public HashSet ArcTargets = new(); + + /// + /// What should this arc to? + /// + [ViewVariables] + [DataField("collisionMask")] + public int CollisionMask = (int) (CollisionGroup.MobMask | CollisionGroup.MachineMask); +} diff --git a/Content.Shared/Lightning/SharedLightningSystem.cs b/Content.Shared/Lightning/SharedLightningSystem.cs new file mode 100644 index 0000000000..dc79a81c32 --- /dev/null +++ b/Content.Shared/Lightning/SharedLightningSystem.cs @@ -0,0 +1,19 @@ +using Robust.Shared.Random; + +namespace Content.Shared.Lightning; + +public abstract class SharedLightningSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + + /// + /// Picks a random sprite state for the lightning. It's just data that gets passed to the + /// + /// Returns a string "lightning_" + the chosen random number. + public string LightningRandomizer() + { + //When the lightning is made with TryCreateBeam, spawns random sprites for each beam to make it look nicer. + var spriteStateNumber = _random.Next(1, 12); + return ("lightning_" + spriteStateNumber); + } +} diff --git a/Resources/Audio/Effects/Lightning/licenses.txt b/Resources/Audio/Effects/Lightning/licenses.txt new file mode 100644 index 0000000000..65cf9df2dc --- /dev/null +++ b/Resources/Audio/Effects/Lightning/licenses.txt @@ -0,0 +1,6 @@ +LightningShock.ogg taken from Citadel Station at commit: https://github.com/Citadel-Station-13/Citadel-Station-13/commit/35a1723e98a60f375df590ca572cc90f1bb80bd5 + +- files: ["LightningShock.ogg"] + license: "CC-BY-NC-SA-3.0" + copyright: "LightningShock.ogg taken from Citadel Station." + source: "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/35a1723e98a60f375df590ca572cc90f1bb80bd5" \ No newline at end of file diff --git a/Resources/Audio/Effects/Lightning/lightningshock.ogg b/Resources/Audio/Effects/Lightning/lightningshock.ogg new file mode 100644 index 0000000000..341a2934d6 Binary files /dev/null and b/Resources/Audio/Effects/Lightning/lightningshock.ogg differ diff --git a/Resources/Prototypes/Entities/Effects/lightning.yml b/Resources/Prototypes/Entities/Effects/lightning.yml new file mode 100644 index 0000000000..88a2032cba --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/lightning.yml @@ -0,0 +1,106 @@ +- type: entity + name: lightning + id: BaseLightning + abstract: true + components: + - type: Sprite + sprite: /Textures/Effects/lightning.rsi + drawdepth: Effects + netsync: false + layers: + - state: "lightning_1" + shader: unshaded + - type: Physics + - type: Electrified + requirePower: false + - type: Lightning + - type: PointLight + enabled: true + color: "#4080FF" + radius: 3.5 + softness: 1 + autoRot: true + castShadows: false + - type: Beam + sound: /Audio/Effects/Lightning/lightningshock.ogg + - type: TimedDespawn + lifetime: 3 + - type: Tag + tags: + - HideContextMenu + +- type: entity + name: lightning + id: Lightning + parent: BaseLightning + components: + - type: Lightning + canArc: true + +- type: entity + name: charged lightning + id: ChargedLightning + parent: BaseLightning + components: + - type: Sprite + sprite: /Textures/Effects/lightning.rsi + drawdepth: Effects + layers: + - state: "blue_lightning" + shader: unshaded + - type: Electrified + requirePower: false + shockDamage: 40 + - type: Lightning + canArc: true + lightningPrototype: ChargedLightning + +- type: entity + name: supercharged lightning + id: SuperchargedLightning + parent: ChargedLightning + components: + - type: Sprite + sprite: /Textures/Effects/lightning.rsi + drawdepth: Effects + layers: + - state: "yellow_lightning" + shader: unshaded + - type: Electrified + requirePower: false + shockDamage: 50 + - type: Lightning + canArc: true + lightningPrototype: SuperchargedLightning + - type: PointLight + enabled: true + color: "#FFFF00" + radius: 3.5 + softness: 1 + autoRot: true + castShadows: false + +- type: entity + name: hypercharged lightning + id: HyperchargedLightning + parent: ChargedLightning + components: + - type: Sprite + sprite: /Textures/Effects/lightning.rsi + drawdepth: Effects + layers: + - state: "red_lightning" + shader: unshaded + - type: Electrified + requirePower: false + shockDamage: 60 + - type: Lightning + canArc: true + lightningPrototype: HyperchargedLightning + - type: PointLight + enabled: true + color: "#ff0000" + radius: 3.5 + softness: 1 + autoRot: true + castShadows: false diff --git a/Resources/Prototypes/Entities/Virtual/beam.yml b/Resources/Prototypes/Entities/Virtual/beam.yml new file mode 100644 index 0000000000..7ded09c3ff --- /dev/null +++ b/Resources/Prototypes/Entities/Virtual/beam.yml @@ -0,0 +1,12 @@ +# Special entity used to keep track of beams from the BeamComponent and what targets they collided with +- type: entity + id: VirtualBeamEntityController + name: BEAM ENTITY YOU SHOULD NOT SEE THIS + noSpawn: true + components: + - type: Beam + - type: TimedDespawn + lifetime: 4 + - type: Tag + tags: + - HideContextMenu diff --git a/Resources/Textures/Effects/lightning.rsi/blue_lightning.png b/Resources/Textures/Effects/lightning.rsi/blue_lightning.png new file mode 100644 index 0000000000..a2b63c9563 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/blue_lightning.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_1.png b/Resources/Textures/Effects/lightning.rsi/lightning_1.png new file mode 100644 index 0000000000..d7d187947d Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_1.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_10.png b/Resources/Textures/Effects/lightning.rsi/lightning_10.png new file mode 100644 index 0000000000..516c8a2fbb Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_10.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_11.png b/Resources/Textures/Effects/lightning.rsi/lightning_11.png new file mode 100644 index 0000000000..2c1de9e27e Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_11.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_12.png b/Resources/Textures/Effects/lightning.rsi/lightning_12.png new file mode 100644 index 0000000000..739f48982b Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_12.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_2.png b/Resources/Textures/Effects/lightning.rsi/lightning_2.png new file mode 100644 index 0000000000..a8d13dc21a Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_2.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_3.png b/Resources/Textures/Effects/lightning.rsi/lightning_3.png new file mode 100644 index 0000000000..649af10dcb Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_3.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_4.png b/Resources/Textures/Effects/lightning.rsi/lightning_4.png new file mode 100644 index 0000000000..c68afc01f9 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_4.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_5.png b/Resources/Textures/Effects/lightning.rsi/lightning_5.png new file mode 100644 index 0000000000..575c86f60b Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_5.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_6.png b/Resources/Textures/Effects/lightning.rsi/lightning_6.png new file mode 100644 index 0000000000..4150ef0d28 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_6.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_7.png b/Resources/Textures/Effects/lightning.rsi/lightning_7.png new file mode 100644 index 0000000000..2a18c12484 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_7.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_8.png b/Resources/Textures/Effects/lightning.rsi/lightning_8.png new file mode 100644 index 0000000000..10226ba849 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_8.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/lightning_9.png b/Resources/Textures/Effects/lightning.rsi/lightning_9.png new file mode 100644 index 0000000000..b038cceca1 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/lightning_9.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/meta.json b/Resources/Textures/Effects/lightning.rsi/meta.json new file mode 100644 index 0000000000..c0845182c2 --- /dev/null +++ b/Resources/Textures/Effects/lightning.rsi/meta.json @@ -0,0 +1,152 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/Citadel-Station-13/Citadel-Station-13/commit/06689416691093474d600924242f69eb7d223f3e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "lightning_1", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_2", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_3", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_4", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_5", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_6", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_7", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_8", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_9", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_10", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_11", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "lightning_12", + "delays": [ + [ + 0.120000005, + 0.08 + ] + ] + }, + { + "name": "yellow_lightning", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "blue_lightning", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "red_lightning", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Effects/lightning.rsi/red_lightning.png b/Resources/Textures/Effects/lightning.rsi/red_lightning.png new file mode 100644 index 0000000000..dd37386174 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/red_lightning.png differ diff --git a/Resources/Textures/Effects/lightning.rsi/yellow_lightning.png b/Resources/Textures/Effects/lightning.rsi/yellow_lightning.png new file mode 100644 index 0000000000..b933aca360 Binary files /dev/null and b/Resources/Textures/Effects/lightning.rsi/yellow_lightning.png differ