diff --git a/Content.Server/_White/Teleporter/ExperimentalTeleporterComponent.cs b/Content.Server/_White/Teleporter/ExperimentalTeleporterComponent.cs new file mode 100644 index 0000000000..c9a773e531 --- /dev/null +++ b/Content.Server/_White/Teleporter/ExperimentalTeleporterComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Audio; + +namespace Content.Server._White.Teleporter; + +[RegisterComponent] +public sealed partial class ExperimentalTeleporterComponent : Component +{ + [DataField] + public int MinTeleportRange = 3; + + [DataField] + public int MaxTeleportRange = 8; + + [DataField] + public int EmergencyLength = 4; + + [DataField] + public List RandomRotations = new() {90, -90}; + + [DataField] + public string? TeleportInEffect = "ExperimentalTeleporterInEffect"; + + [DataField] + public string? TeleportOutEffect = "ExperimentalTeleporterOutEffect"; + + [DataField] + public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/_White/Object/Devices/experimentalsyndicateteleport.ogg"); +} diff --git a/Content.Server/_White/Teleporter/ExperimentalTeleporterSystem.cs b/Content.Server/_White/Teleporter/ExperimentalTeleporterSystem.cs new file mode 100644 index 0000000000..4a4fc5dab4 --- /dev/null +++ b/Content.Server/_White/Teleporter/ExperimentalTeleporterSystem.cs @@ -0,0 +1,114 @@ +using System.Linq; +using System.Numerics; +using Content.Server.Body.Systems; +using Content.Server.Standing; +using Content.Shared.Charges.Systems; +using Content.Shared.Coordinates.Helpers; +using Content.Shared.Interaction.Events; +using Content.Shared.Maps; +using Content.Shared.Tag; +using Robust.Server.Audio; +using Robust.Server.Containers; +using Robust.Server.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Random; + +namespace Content.Server._White.Teleporter; + +public sealed class ExperimentalTeleporterSystem : EntitySystem +{ + [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly BodySystem _bodySystem = default!; + [Dependency] private readonly MapSystem _mapSystem = default!; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly ContainerSystem _containerSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly LayingDownSystem _layingDown = default!; + [Dependency] private readonly SharedChargesSystem _charges = default!; + [Dependency] private readonly TagSystem _tag = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnUse); + } + + private void OnUse(EntityUid uid, ExperimentalTeleporterComponent component, UseInHandEvent args) + { + if (_charges.IsEmpty(uid) + || !TryComp(args.User, out var xform) + || (_containerSystem.IsEntityInContainer(args.User) + && !_containerSystem.TryRemoveFromContainer(args.User))) + return; + + var oldCoords = xform.Coordinates; + var range = _random.Next(component.MinTeleportRange, component.MaxTeleportRange); + var offset = xform.LocalRotation.ToWorldVec().Normalized(); + var direction = xform.LocalRotation.GetDir().ToVec(); + var newOffset = offset + direction * range; + + var coords = xform.Coordinates.Offset(newOffset).SnapToGrid(EntityManager); + + Teleport(args.User, uid, component, coords, oldCoords); + + if (!TryCheckWall(coords) + || EmergencyTeleportation(args.User, uid, component, xform, oldCoords, newOffset)) + return; + + _bodySystem.GibBody(args.User, true, splatModifier: 3F); + } + + private bool EmergencyTeleportation(EntityUid uid, EntityUid teleporterUid, ExperimentalTeleporterComponent component, TransformComponent xform, EntityCoordinates oldCoords, Vector2 offset) + { + var newOffset = offset + VectorRandomDirection(component, offset, component.EmergencyLength); + var coords = xform.Coordinates.Offset(newOffset).SnapToGrid(EntityManager); + + if (_charges.IsEmpty(teleporterUid)) + return false; + + Teleport(uid, teleporterUid, component, coords, oldCoords); + + return !TryCheckWall(coords); + } + + private void Teleport(EntityUid uid, EntityUid teleporterUid, ExperimentalTeleporterComponent component, EntityCoordinates coords, EntityCoordinates oldCoords) + { + PlaySoundAndEffects(component, coords, oldCoords); + + _layingDown.LieDownInRange(uid, coords); + _transform.SetCoordinates(uid, coords); + + _charges.UseCharge(teleporterUid); + } + + private void PlaySoundAndEffects(ExperimentalTeleporterComponent component, EntityCoordinates coords, EntityCoordinates oldCoords) + { + _audio.PlayPvs(component.TeleportSound, coords); + _audio.PlayPvs(component.TeleportSound, oldCoords); + + _entManager.SpawnEntity(component.TeleportInEffect, coords); + _entManager.SpawnEntity(component.TeleportOutEffect, oldCoords); + } + + private bool TryCheckWall(EntityCoordinates coords) + { + if (!coords.TryGetTileRef(out var tile) + || !TryComp(tile.Value.GridUid, out var mapGridComponent)) + return false; + + var anchoredEntities = _mapSystem.GetAnchoredEntities(tile.Value.GridUid, mapGridComponent, coords); + + return anchoredEntities.Any(x => _tag.HasTag(x, "Wall")); + } + + private Vector2 VectorRandomDirection(ExperimentalTeleporterComponent component, Vector2 offset, int length) + { + if (component.RandomRotations.Count == 0) + return Vector2.Zero; + + var randomRotation = _random.Next(0, component.RandomRotations.Count); + return Angle.FromDegrees(component.RandomRotations[randomRotation]).RotateVec(offset.Normalized() * length); + } +} diff --git a/Resources/Audio/_White/Object/Devices/attributions.yml b/Resources/Audio/_White/Object/Devices/attributions.yml new file mode 100644 index 0000000000..a8950150f7 --- /dev/null +++ b/Resources/Audio/_White/Object/Devices/attributions.yml @@ -0,0 +1,4 @@ +- files: ["experimentalsyndicateteleport.ogg"] + license: "CC-BY-NC-SA-4.0" + copyright: "Taken from White Dream" + source: "https://github.com/frosty-dev/ss14-core/blob/master/Resources/Audio/White/Devices/expsyndicateteleport.ogg" \ No newline at end of file diff --git a/Resources/Audio/_White/Object/Devices/experimentalsyndicateteleport.ogg b/Resources/Audio/_White/Object/Devices/experimentalsyndicateteleport.ogg new file mode 100644 index 0000000000..37a5b3839c Binary files /dev/null and b/Resources/Audio/_White/Object/Devices/experimentalsyndicateteleport.ogg differ diff --git a/Resources/Locale/en-US/_white/store/uplink-catalog.ftl b/Resources/Locale/en-US/_white/store/uplink-catalog.ftl index b4edcee7dd..f80d022535 100644 --- a/Resources/Locale/en-US/_white/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/_white/store/uplink-catalog.ftl @@ -4,5 +4,8 @@ uplink-emp-flashlight-desc = A rechargeable device disguised as a flashlight des uplink-betrayal-knife-name = Betrayal dagger uplink-betrayal-knife-desc = The betrayal dagger allows the user to teleport a short distance, and also causes significant damage when stabbed in the back. +uplink-betrayal-knife-name = Experimental syndicate teleporter +uplink-betrayal-knife-desc = Syndicate teleporter, when used, moves 3-8 meters forward. In case of teleportation into a wall, uses emergency teleportation. Has 4 charge. + uplink-ebow-name = Small energy crossbow -uplink-ebow-desc = A fairly quiet weapon that automatically reloads and stuns. It goes well with other types of weapons. \ No newline at end of file +uplink-ebow-desc = A fairly quiet weapon that automatically reloads and stuns. It goes well with other types of weapons. diff --git a/Resources/Locale/ru-RU/_white/prototypes/entities/objects/device/syndicate_gadgets/experimental-teleporter.ftl b/Resources/Locale/ru-RU/_white/prototypes/entities/objects/device/syndicate_gadgets/experimental-teleporter.ftl new file mode 100644 index 0000000000..f9359375ac --- /dev/null +++ b/Resources/Locale/ru-RU/_white/prototypes/entities/objects/device/syndicate_gadgets/experimental-teleporter.ftl @@ -0,0 +1,2 @@ +ent-ExperimentalSyndicateTeleporter = экспериментальный телепортер синдиката + .desc = Телепортер синдиката, при использовании перемещает на 3-8 метров вперед. В случае телепортации в стену, использует экстренную телепортацию. Имеет 4 заряда и автоматически заряжается. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_white/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/_white/store/uplink-catalog.ftl index 025ac86b8e..8d58a4bc17 100644 --- a/Resources/Locale/ru-RU/_white/store/uplink-catalog.ftl +++ b/Resources/Locale/ru-RU/_white/store/uplink-catalog.ftl @@ -4,5 +4,8 @@ uplink-emp-flashlight-desc = Замаскированное под фонари uplink-betrayal-knife-name = Предательский кинжал uplink-betrayal-knife-desc = Предательский кинжал позволяет пользователю телепортироваться на короткое расстояние, а также наносит значительные повреждения при ударе в спину. +uplink-experimental-syndicate-teleporter-name = Экспериментальный телепортер синдиката +uplink-experimental-syndicate-teleporter-desc = Телепортер синдиката, при использовании перемещает на 3-8 метров вперед. В случае телепортации в стену, использует экстренную телепортацию. Имеет 4 заряда и автоматически заряжается. + uplink-ebow-name = Маленький энергетический арбалет -uplink-ebow-desc = Довольно тихое оружие, которое автоматически перезаряжается и оглушает. Хорошо сочетается с другими видами оружия. \ No newline at end of file +uplink-ebow-desc = Довольно тихое оружие, которое автоматически перезаряжается и оглушает. Хорошо сочетается с другими видами оружия. diff --git a/Resources/Prototypes/_White/Catalog/uplink_catalog.yml b/Resources/Prototypes/_White/Catalog/uplink_catalog.yml index 43f9330c03..c58efd96c6 100644 --- a/Resources/Prototypes/_White/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/_White/Catalog/uplink_catalog.yml @@ -8,6 +8,16 @@ categories: - UplinkUtility +- type: listing + id: UplinkExperimentalSyndicateTeleporter + name: uplink-experimental-syndicate-teleporter-name + description: uplink-experimental-syndicate-teleporter-desc + productEntity: ExperimentalSyndicateTeleporter + cost: + Telecrystal: 10 + categories: + - UplinkUtility + - type: listing id: UplinkBetrayalKnife name: uplink-betrayal-knife-name diff --git a/Resources/Prototypes/_White/Entities/Effects/effects.yml b/Resources/Prototypes/_White/Entities/Effects/effects.yml new file mode 100644 index 0000000000..2c20be01c5 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Effects/effects.yml @@ -0,0 +1,39 @@ +- type: entity + id: ExperimentalTeleporterInEffect + name: experimental syndicate teleporter in effect + components: + - type: TimedDespawn + lifetime: 0.6 + - type: EvaporationSparkle + - type: Transform + noRot: true + anchored: true + - type: Sprite + layers: + - sprite: /Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi + state: in + shader: unshaded + netsync: false + drawdepth: Effects + - type: PointLight + color: "#008DFE" + +- type: entity + id: ExperimentalTeleporterOutEffect + name: experimental syndicate teleporter out effect + components: + - type: TimedDespawn + lifetime: 0.6 + - type: EvaporationSparkle + - type: Transform + noRot: true + anchored: true + - type: Sprite + layers: + - sprite: /Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi + state: out + shader: unshaded + netsync: false + drawdepth: Effects + - type: PointLight + color: "#008DFE" \ No newline at end of file diff --git a/Resources/Prototypes/_White/Entities/Objects/Devices/Syndicate_Gadgets/experimental_teleporter.yml b/Resources/Prototypes/_White/Entities/Objects/Devices/Syndicate_Gadgets/experimental_teleporter.yml new file mode 100644 index 0000000000..9bade18288 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Objects/Devices/Syndicate_Gadgets/experimental_teleporter.yml @@ -0,0 +1,16 @@ +- type: entity + id: ExperimentalSyndicateTeleporter + parent: BaseItem + name: experimental syndicate teleporter + description: Syndicate teleporter, when used, moves 3-8 meters forward. In case of teleportation into a wall, uses emergency teleportation. Has 4 charge. + components: + - type: Sprite + sprite: /Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi + layers: + - state: icon + - type: ExperimentalTeleporter + - type: LimitedCharges + maxCharges: 4 + charges: 4 + - type: AutoRecharge + rechargeDuration: 10 \ No newline at end of file diff --git a/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png new file mode 100644 index 0000000000..106f3f415c Binary files /dev/null and b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png differ diff --git a/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png new file mode 100644 index 0000000000..456e592a33 Binary files /dev/null and b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png differ diff --git a/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png new file mode 100644 index 0000000000..1b5ed5d077 Binary files /dev/null and b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png differ diff --git a/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png new file mode 100644 index 0000000000..ff383c0354 Binary files /dev/null and b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png differ diff --git a/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/meta.json b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/meta.json new file mode 100644 index 0000000000..038ce06e4b --- /dev/null +++ b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/meta.json @@ -0,0 +1,122 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation, remade by CaypenNow", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "in", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "out", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 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/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png new file mode 100644 index 0000000000..6483dbcc3b Binary files /dev/null and b/Resources/Textures/_White/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png differ