diff --git a/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlay.cs b/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlay.cs new file mode 100644 index 000000000000..036a30817911 --- /dev/null +++ b/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlay.cs @@ -0,0 +1,76 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using System.Numerics; +using Content.Shared.SS220.ForcefieldGenerator; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; + +namespace Content.Client.SS220.ForcefieldGenerator; + +public sealed class ForcefieldOverlay : Overlay +{ + private EntityManager _entity; + private SharedTransformSystem _transform; + private IPrototypeManager _prototype = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities; + public override bool RequestScreenTexture => true; + + private readonly ShaderInstance _shader; + private readonly ShaderInstance _shader_unshaded; + + public ForcefieldOverlay(EntityManager entMan, IPrototypeManager protoMan) + { + _entity = entMan; + _transform = entMan.EntitySysManager.GetEntitySystem(); + _prototype = protoMan; + _shader_unshaded = _prototype.Index("unshaded").InstanceUnique(); + _shader = _prototype.Index("Stealth").InstanceUnique(); + + ZIndex = (int) Shared.DrawDepth.DrawDepth.Overdoors; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture == null) + return; + + var handle = args.WorldHandle; + var queryEnum = _entity.EntityQueryEnumerator(); + + while (queryEnum.MoveNext(out var uid, out var fieldComp)) + { + if (fieldComp.Generator is not { } generator || !_entity.EntityExists(generator)) + { + continue; + } + + if (!_entity.TryGetComponent(generator, out var generatorComp)) + { + continue; + } + + var boxToRender = new Box2( + new Vector2(-generatorComp.FieldLength / 2, -generatorComp.FieldThickness / 2), + new Vector2(generatorComp.FieldLength / 2, generatorComp.FieldThickness / 2) + ); + + var (position, rotation) = _transform.GetWorldPositionRotation(uid); + + var reference = args.Viewport.WorldToLocal(position); + reference.X = -reference.X; + + _shader.SetParameter("SCREEN_TEXTURE", ScreenTexture); + _shader.SetParameter("reference", reference); + var finalVisibility = Math.Clamp(generatorComp.FieldVisibility, -1f, 1f); + _shader.SetParameter("visibility", finalVisibility); + + handle.SetTransform(position, rotation); + handle.UseShader(_shader); + handle.DrawRect(boxToRender, generatorComp.FieldColor); + } + + handle.UseShader(null); + handle.SetTransform(Matrix3.Identity); + } +} diff --git a/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlaySystem.cs b/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlaySystem.cs new file mode 100644 index 000000000000..e4b0401e4c62 --- /dev/null +++ b/Content.Client/SS220/ForcefieldGenerator/ForcefieldOverlaySystem.cs @@ -0,0 +1,27 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Robust.Client.Graphics; +using Robust.Shared.Prototypes; + +namespace Content.Client.SS220.ForcefieldGenerator; + +public sealed class ForcefieldOverlaySystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayManager = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + + private ForcefieldOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + _overlay = new(this.EntityManager, _prototype); + _overlayManager.AddOverlay(_overlay); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlayManager.RemoveOverlay(_overlay); + } +} diff --git a/Content.Server/SS220/ForcefieldGenerator/ForcefieldGeneratorSystem.cs b/Content.Server/SS220/ForcefieldGenerator/ForcefieldGeneratorSystem.cs new file mode 100644 index 000000000000..5b577444831c --- /dev/null +++ b/Content.Server/SS220/ForcefieldGenerator/ForcefieldGeneratorSystem.cs @@ -0,0 +1,332 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using System.Numerics; +using Content.Server.Audio; +using Content.Server.DeviceLinking.Events; +using Content.Server.Popups; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Damage; +using Content.Shared.SS220.ForcefieldGenerator; +using Robust.Server.Audio; +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.Systems; + +namespace Content.Server.SS220.ForcefieldGenerator; + +public sealed class ForcefieldGeneratorSystem : EntitySystem +{ + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly FixtureSystem _fixture = default!; + [Dependency] private readonly PhysicsSystem _physics = default!; + [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly PointLightSystem _pointLight = default!; + [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly AmbientSoundSystem _ambientSound = default!; + + private EntityQuery _physicsQuery; + + public override void Initialize() + { + SubscribeLocalEvent(OnComponentShutdown); + SubscribeLocalEvent(OnSignalReceived); + SubscribeLocalEvent(OnChargeChanged); + SubscribeLocalEvent(OnDamageReceived); + + _physicsQuery = GetEntityQuery(); + } + + private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) + { + ClearShieldEntity(entity.Comp); + } + + private void OnChargeChanged(Entity entity, ref ChargeChangedEvent args) + { + UpdateAppearance(entity); + } + + private void OnSignalReceived(Entity entity, ref SignalReceivedEvent args) + { + if (args.Port == entity.Comp.TogglePort) + SetActive(entity, !entity.Comp.Active); + } + + private void OnDamageReceived(Entity entity, ref DamageChangedEvent args) + { + if (args.DamageDelta is not { } damageDelta) + return; + + if (entity.Comp.Generator is not { } generator) + return; + + if (!Exists(generator)) + return; + + if (!TryComp(generator, out var genComp)) + return; + + var totalEnergyDraw = damageDelta.GetTotal().Float() * genComp.DamageToEnergyCoefficient; + if (totalEnergyDraw <= 0) + return; + + _battery.UseCharge(generator, totalEnergyDraw); + _audio.PlayPvs(entity.Comp.HitSound, entity); + } + + private EntityUid? GetFieldEntity(ForcefieldGeneratorSS220Component comp) + { + if (comp.FieldEntity is { } existing) + { + if (!Deleted(existing) && !EntityManager.IsQueuedForDeletion(existing)) + return existing; + } + + return null; + } + + private EntityUid EnsureFieldEntity(Entity entity) + { + if (GetFieldEntity(entity) is { } existing) + return existing; + + var newFieldEntity = Spawn(entity.Comp.ShieldProto, Transform(entity).Coordinates); + entity.Comp.FieldEntity = newFieldEntity; + + if (TryComp(newFieldEntity, out var forcefieldComp)) + { + forcefieldComp.Generator = entity; + Dirty(entity, forcefieldComp); + } + + UpdateFieldFixture(entity); + + return newFieldEntity; + } + + private void ClearShieldEntity(ForcefieldGeneratorSS220Component comp) + { + if (comp.FieldEntity != null) + { + QueueDel(comp.FieldEntity); + comp.FieldEntity = null; + } + } + + public void SetFieldLength(Entity entity, float length) + { + entity.Comp.FieldLength = length; + Dirty(entity); + UpdateFieldFixture(entity); + } + + private void UpdateFieldFixture(Entity entity) + { + var shieldEntity = GetFieldEntity(entity.Comp); + if (!shieldEntity.HasValue) + return; + + if (!TryComp(shieldEntity, out var fixtures)) + return; + + var oldFixture = _fixture.GetFixtureOrNull( + shieldEntity.Value, + ForcefieldGeneratorSS220Component.FIELD_FIXTURE_NAME, + fixtures); + + if (oldFixture is null) + return; + + // retain properties that were specified in proto + var density = oldFixture.Density; + var mask = oldFixture.CollisionMask; + var layer = oldFixture.CollisionLayer; + + // define shape + var shape = new PolygonShape(); + var box = new Box2( + new Vector2(-entity.Comp.FieldLength / 2, -entity.Comp.FieldThickness / 2), + new Vector2(entity.Comp.FieldLength / 2, entity.Comp.FieldThickness / 2) + ); + shape.SetAsBox(box); + + Log.Debug("Shield fixture update"); + + _fixture.DestroyFixture( + shieldEntity.Value, + ForcefieldGeneratorSS220Component.FIELD_FIXTURE_NAME, + false, + manager: fixtures + ); + + _fixture.TryCreateFixture( + shieldEntity.Value, + shape, + ForcefieldGeneratorSS220Component.FIELD_FIXTURE_NAME, + density: density, + collisionLayer: layer, + collisionMask: mask, + manager: fixtures, + updates: false + ); + + _fixture.FixtureUpdate(shieldEntity.Value, manager: fixtures); + } + + private void UpdateFieldPosition(EntityUid entity, ForcefieldGeneratorSS220Component component) + { + var fieldEntity = GetFieldEntity(component); + if (!fieldEntity.HasValue) + return; + + var genTransform = Transform(entity); + var pos = Matrix3.CreateRotation(component.Angle).Transform(new Vector2(0, component.Radius)); + _transform.SetCoordinates(fieldEntity.Value, new EntityCoordinates(entity, pos)); + _transform.SetWorldRotation(fieldEntity.Value, _transform.GetWorldRotation(genTransform) + component.Angle); + + // sending entity to nullspace apparently disables canCollide, so we need to ensure its on + if (_physicsQuery.TryGetComponent(fieldEntity, out var physicsComp)) + { + if (!physicsComp.CanCollide) + _physics.SetCanCollide(fieldEntity.Value, true, true, true, body: physicsComp); + } + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.FieldEnabled) + UpdateFieldPosition(uid, comp); + + if (comp.Active) + { + _battery.UseCharge(uid, comp.EnergyUpkeep * frameTime); + UpdateFieldActivity(new(uid, comp)); + } + } + } + + private void SetFieldEnabled(Entity entity, bool enabled) + { + if (enabled) + EnsureFieldEntity(entity); + else + ClearShieldEntity(entity.Comp); + + var changed = entity.Comp.FieldEnabled != enabled; + entity.Comp.FieldEnabled = enabled; + + if (changed) + { + Dirty(entity); + + if (!enabled) + { + if (TryComp(entity, out var battery) && battery.CurrentCharge <= 0) + { + _popup.PopupEntity( + Loc.GetString("forcefield-generator-ss220-unpowered"), + entity, + Shared.Popups.PopupType.MediumCaution + ); + } + else + { + _popup.PopupEntity( + Loc.GetString("forcefield-generator-ss220-disabled"), + entity, + Shared.Popups.PopupType.Medium + ); + } + } + else + { + _popup.PopupEntity( + Loc.GetString("forcefield-generator-ss220-enabled"), + entity, + Shared.Popups.PopupType.Medium + ); + } + + var sound = enabled ? entity.Comp.GeneratorOnSound : entity.Comp.GeneratorOffSound; + _audio.PlayPvs(sound, entity); + _ambientSound.SetAmbience(entity, enabled); + } + } + + private void UpdateFieldActivity(Entity entity) + { + if (entity.Comp.Active) + { + if (TryComp(entity, out var battery) && battery.CurrentCharge > 0) + { + SetFieldEnabled(entity, true); + return; + } + } + + SetFieldEnabled(entity, false); + } + + private void UpdateAppearance(Entity entity) + { + _appearance.SetData(entity, ForcefieldGeneratorVisual.Active, entity.Comp.Active); + + if (TryComp(entity, out var battery)) + { + var charge = battery.CurrentCharge / battery.MaxCharge; + var powerVisualState = charge switch + { + (>= 0.95f) => ForcefieldGeneratorVisual.Power_4, + (>= 0.65f and < 0.95f) => ForcefieldGeneratorVisual.Power_3, + (>= 0.3f and < 0.65f) => ForcefieldGeneratorVisual.Power_2, + (< 0.3f) => ForcefieldGeneratorVisual.Power_1, + _ => ForcefieldGeneratorVisual.Power_1 + }; + + _appearance.SetData( + entity, + ForcefieldGeneratorVisual.Power_1, + powerVisualState == ForcefieldGeneratorVisual.Power_1); + _appearance.SetData( + entity, + ForcefieldGeneratorVisual.Power_2, + powerVisualState == ForcefieldGeneratorVisual.Power_2); + _appearance.SetData( + entity, + ForcefieldGeneratorVisual.Power_3, + powerVisualState == ForcefieldGeneratorVisual.Power_3); + _appearance.SetData( + entity, + ForcefieldGeneratorVisual.Power_4, + powerVisualState == ForcefieldGeneratorVisual.Power_4); + } + } + + public void SetActive(Entity entity, bool active) + { + Log.Debug("Field active: " + active.ToString()); + + if (active) + { + if (!TryComp(entity, out var battery) || battery.Charge < battery.MaxCharge) + return; + } + + entity.Comp.Active = active; + _pointLight.SetEnabled(entity, active); + + UpdateAppearance(entity); + UpdateFieldActivity(entity); + Dirty(entity); + } +} diff --git a/Content.Shared/SS220/ForcefieldGenerator/ForcefieldGeneratorSS220Component.cs b/Content.Shared/SS220/ForcefieldGenerator/ForcefieldGeneratorSS220Component.cs new file mode 100644 index 000000000000..a6dc5a31ea58 --- /dev/null +++ b/Content.Shared/SS220/ForcefieldGenerator/ForcefieldGeneratorSS220Component.cs @@ -0,0 +1,96 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Content.Shared.DeviceLinking; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.SS220.ForcefieldGenerator; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ForcefieldGeneratorSS220Component : Component +{ + public const string FIELD_FIXTURE_NAME = "fix1"; + + /// + /// How long the forcefield is + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public float FieldLength = 3; + + /// + /// How long the forcefield is + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public float FieldThickness = 0.5f; + + /// + /// Forcefield angle + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public Angle Angle = 0; + + /// + /// Offset from the center of the generator, direction of the offset matches the angle of field + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public float Radius = 3; + + /// + /// How much energy it costs per seond to keep the field up + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public float EnergyUpkeep = 183; + + /// + /// How much energy it consumes per 1 unit of damage + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public float DamageToEnergyCoefficient = 15; + + /// + /// Whether the GENERATOR is active or not + /// + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public bool Active = false; + + /// + /// Whether the FIELD is active or not + /// + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public bool FieldEnabled = false; + + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public Color FieldColor = Color.LightBlue; + + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public float FieldVisibility = 0.1f; + + [ViewVariables(VVAccess.ReadOnly)] + public SoundSpecifier GeneratorIdleSound = new SoundPathSpecifier("/Audio/SS220/Effects/shield/eshild_loop.ogg"); + + [ViewVariables(VVAccess.ReadOnly)] + public SoundSpecifier GeneratorOnSound = new SoundPathSpecifier("/Audio/SS220/Effects/shield/eshild_on.ogg"); + + [ViewVariables(VVAccess.ReadOnly)] + public SoundSpecifier GeneratorOffSound = new SoundPathSpecifier("/Audio/SS220/Effects/shield/eshild_off.ogg"); + + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? FieldEntity; + + [DataField] + public ProtoId TogglePort = "Toggle"; + + [DataField] + public EntProtoId ShieldProto = "forcefield220"; +} + +[NetSerializable, Serializable] +public enum ForcefieldGeneratorVisual +{ + Active, + Power_1, + Power_2, + Power_3, + Power_4 +} diff --git a/Content.Shared/SS220/ForcefieldGenerator/ForcefieldSS220Component.cs b/Content.Shared/SS220/ForcefieldGenerator/ForcefieldSS220Component.cs new file mode 100644 index 000000000000..5620c193eddd --- /dev/null +++ b/Content.Shared/SS220/ForcefieldGenerator/ForcefieldSS220Component.cs @@ -0,0 +1,18 @@ +// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.SS220.ForcefieldGenerator; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ForcefieldSS220Component : Component +{ + [ViewVariables(VVAccess.ReadOnly), AutoNetworkedField] + public EntityUid? Generator; + + [ViewVariables(VVAccess.ReadOnly)] + public SoundSpecifier HitSound = new SoundPathSpecifier("/Audio/SS220/Effects/shield/eshild_hit.ogg", new() + { + Volume = 1.25f + }); +} diff --git a/Resources/Audio/SS220/Effects/shield/attributions.yml b/Resources/Audio/SS220/Effects/shield/attributions.yml new file mode 100644 index 000000000000..31b7225245ab --- /dev/null +++ b/Resources/Audio/SS220/Effects/shield/attributions.yml @@ -0,0 +1,4 @@ +- files: ["eshild_hit.ogg","eshild_loop.ogg","eshild_off.ogg","eshild_on.ogg"] + license: "Custom" + copyright: "Made by MIXnikita for SS220. Licensed under an EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt" + source: "https://github.com/SerbiaStrong-220/space-station-14" \ No newline at end of file diff --git a/Resources/Audio/SS220/Effects/shield/eshild_hit.ogg b/Resources/Audio/SS220/Effects/shield/eshild_hit.ogg new file mode 100644 index 000000000000..f1b1ea3a02c5 Binary files /dev/null and b/Resources/Audio/SS220/Effects/shield/eshild_hit.ogg differ diff --git a/Resources/Audio/SS220/Effects/shield/eshild_loop.ogg b/Resources/Audio/SS220/Effects/shield/eshild_loop.ogg new file mode 100644 index 000000000000..7e556c46a0ac Binary files /dev/null and b/Resources/Audio/SS220/Effects/shield/eshild_loop.ogg differ diff --git a/Resources/Audio/SS220/Effects/shield/eshild_off.ogg b/Resources/Audio/SS220/Effects/shield/eshild_off.ogg new file mode 100644 index 000000000000..d4d5a300f47f Binary files /dev/null and b/Resources/Audio/SS220/Effects/shield/eshild_off.ogg differ diff --git a/Resources/Audio/SS220/Effects/shield/eshild_on.ogg b/Resources/Audio/SS220/Effects/shield/eshild_on.ogg new file mode 100644 index 000000000000..eadcee5f0d89 Binary files /dev/null and b/Resources/Audio/SS220/Effects/shield/eshild_on.ogg differ diff --git a/Resources/Locale/ru-RU/ss220/forcefield.ftl b/Resources/Locale/ru-RU/ss220/forcefield.ftl new file mode 100644 index 000000000000..97dd9284d153 --- /dev/null +++ b/Resources/Locale/ru-RU/ss220/forcefield.ftl @@ -0,0 +1,3 @@ +forcefield-generator-ss220-unpowered = Энергия закончилась! +forcefield-generator-ss220-enabled = Генератор поля запускается. +forcefield-generator-ss220-disabled = Генератор поля отключается. diff --git a/Resources/Prototypes/SS220/Entities/Structures/Machines/forcefield.yml b/Resources/Prototypes/SS220/Entities/Structures/Machines/forcefield.yml new file mode 100644 index 000000000000..acb7135837f5 --- /dev/null +++ b/Resources/Prototypes/SS220/Entities/Structures/Machines/forcefield.yml @@ -0,0 +1,129 @@ +# © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +- type: entity + id: forcefield220 + name: силовое поле + description: Продвинутая технология в действии. Способно спасти вас от баллистического снаряда, но абсолютно бесполезно против лазерного оружия. + noSpawn: true + save: false + components: + - type: Damageable + damageContainer: StructuralInorganic + - type: ForcefieldSS220 + - type: Clickable + - type: Physics + bodyType: Static + canCollide: true + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-1.5,-0.25,1.5,0.25" + density: 100 + mask: + - None + layer: + - BulletImpassable + +- type: entity + parent: BaseStructure + id: forcefieldGenerator220 + name: генератор силового поля + description: Генерирует направленное силовое поле, которое препятствует прониканию баллистических снарядов, но не способно сдерживать лазерное оружие. + components: + - type: ForcefieldGeneratorSS220 + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.4 + density: 190 + mask: + - FullTileMask + layer: + - WallLayer + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: BasicDevice + - type: WirelessNetworkConnection + range: 200 + - type: DeviceLinkSink + ports: + - Toggle + - type: InteractionOutline + - type: Anchorable + - type: Sprite + sprite: SS220/Structures/Machines/EShieldSuttle.rsi + state: base + noRot: true + layers: + - state: base + - state: power_1 + map: ["powerLight"] + shader: unshaded + - state: light_on + map: ["activeLight"] + visible: false + shader: unshaded + - type: GenericVisualizer + visuals: + enum.ForcefieldGeneratorVisual.Active: + activeLight: + True: {visible: true} + False: {visible: false} + enum.ForcefieldGeneratorVisual.Power_1: + powerLight: + True: {state: power_1} + enum.ForcefieldGeneratorVisual.Power_2: + powerLight: + True: {state: power_2} + enum.ForcefieldGeneratorVisual.Power_3: + powerLight: + True: {state: power_3} + enum.ForcefieldGeneratorVisual.Power_4: + powerLight: + True: {state: power_4} + - type: Damageable + damageContainer: StructuralInorganic + damageModifierSet: StrongMetallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1000 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - type: PointLight + enabled: false + color: "#4080FF" + radius: 1.3 + energy: 4.0 + softness: 8.0 + - type: Appearance + - type: Battery + startingCharge: 0 + maxCharge: 5000 + - type: ExaminableBattery + - type: BatteryCharger + voltage: Medium + node: input + - type: PowerNetworkBattery + canSupply: false + maxSupply: 0 + maxChargeRate: 100 + supplyRampTolerance: 5000 + supplyRampRate: 1000 + - type: NodeContainer + examinable: true + nodes: + input: + !type:CableDeviceNode + nodeGroupID: MVPower + - type: AmbientSound + volume: 0 + range: 6 + enabled: false + sound: + path: /Audio/SS220/Effects/shield/eshild_loop.ogg diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/base.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/base.png new file mode 100644 index 000000000000..727a5ca40b02 Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/base.png differ diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/light_on.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/light_on.png new file mode 100644 index 000000000000..3a97e7b76e2f Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/light_on.png differ diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/meta.json b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/meta.json new file mode 100644 index 000000000000..ef79a7144db0 --- /dev/null +++ b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/meta.json @@ -0,0 +1,66 @@ +{ + "version": 1, + "license": "EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt", + "copyright": "by MIXnikita for SS220", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "light_on", + "delays": + [ + [ + 0.2, + 0.1, + 0.2, + 0.1 + ] + ] + }, + { + "name": "power_1", + "delays": + [ + [ + 0.4, + 0.2 + ] + ] + }, + { + "name": "power_2", + "delays": + [ + [ + 0.4, + 0.2 + ] + ] + }, + { + "name": "power_3", + "delays": + [ + [ + 0.4, + 0.2 + ] + ] + }, + { + "name": "power_4", + "delays": + [ + [ + 0.4, + 0.2 + ] + ] + } + ] +} diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_1.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_1.png new file mode 100644 index 000000000000..71da4487ec8b Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_1.png differ diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_2.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_2.png new file mode 100644 index 000000000000..f71b5c79be65 Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_2.png differ diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_3.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_3.png new file mode 100644 index 000000000000..d5a0bda7a518 Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_3.png differ diff --git a/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_4.png b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_4.png new file mode 100644 index 000000000000..4afaaaf7c8f1 Binary files /dev/null and b/Resources/Textures/SS220/Structures/Machines/EShieldSuttle.rsi/power_4.png differ