diff --git a/Content.Server/Backmen/Teleporter/ExperimentalTeleporterComponent.cs b/Content.Server/Backmen/Teleporter/ExperimentalTeleporterComponent.cs new file mode 100644 index 00000000000..cfab6a775d3 --- /dev/null +++ b/Content.Server/Backmen/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/Backmen/Object/Devices/experimentalsyndicateteleport.ogg"); +} diff --git a/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs b/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs new file mode 100644 index 00000000000..5880359a7f9 --- /dev/null +++ b/Content.Server/Backmen/Teleporter/ExperimentalTeleporterSystem.cs @@ -0,0 +1,117 @@ +using Content.Shared.Ghost; +using System.Linq; +using System.Numerics; +using Content.Server.Body.Systems; +using Content.Server.Standing; +using Content.Shared.Backmen.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 SharedLayingDownSystem _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) + || HasComp(args.User)) + 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/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs b/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs index d17b13d1fba..c1e5426b07b 100644 --- a/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs +++ b/Content.Shared/Backmen/Standing/SharedLayingDownSystem.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Shared.Backmen.CCVar; using Content.Shared.Backmen.Targeting; using Content.Shared.Body.Components; @@ -27,6 +28,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.Input.Binding; +using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Network; using Robust.Shared.Physics; @@ -55,6 +57,7 @@ public abstract class SharedLayingDownSystem : EntitySystem [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly IConfigurationManager _config = default!; @@ -356,6 +359,18 @@ standingState.CurrentState is not StandingState.Standing || _standing.Down(uid, true, behavior != DropHeldItemsBehavior.NoDrop, standingState: standingState); return true; } + + // WWDP + public void LieDownInRange(EntityUid uid, EntityCoordinates coords, float range = 0.4f) + { + var ents = new HashSet>(); + _lookup.GetEntitiesInRange(coords, range, ents); + + foreach (var ent in ents.Where(ent => ent.Owner != uid)) + { + TryLieDown(ent, behavior: DropHeldItemsBehavior.DropIfStanding); + } + } } [Serializable, NetSerializable] diff --git a/Resources/Audio/Backmen/Object/Devices/attributions.yml b/Resources/Audio/Backmen/Object/Devices/attributions.yml new file mode 100644 index 00000000000..a8950150f79 --- /dev/null +++ b/Resources/Audio/Backmen/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/Backmen/Object/Devices/experimentalsyndicateteleport.ogg b/Resources/Audio/Backmen/Object/Devices/experimentalsyndicateteleport.ogg new file mode 100644 index 00000000000..37a5b3839c3 Binary files /dev/null and b/Resources/Audio/Backmen/Object/Devices/experimentalsyndicateteleport.ogg differ diff --git a/Resources/Locale/en-US/_backmen/store/uplink-catalog.ftl b/Resources/Locale/en-US/_backmen/store/uplink-catalog.ftl new file mode 100644 index 00000000000..7e8fc8de95e --- /dev/null +++ b/Resources/Locale/en-US/_backmen/store/uplink-catalog.ftl @@ -0,0 +1,3 @@ +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. + diff --git a/Resources/Locale/ru-RU/_backmen/Entities/Objects/device/syndicate_gadgets/experimental-teleporter.ftl b/Resources/Locale/ru-RU/_backmen/Entities/Objects/device/syndicate_gadgets/experimental-teleporter.ftl new file mode 100644 index 00000000000..f9359375ac8 --- /dev/null +++ b/Resources/Locale/ru-RU/_backmen/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/_backmen/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/_backmen/store/uplink-catalog.ftl new file mode 100644 index 00000000000..9301571c0c6 --- /dev/null +++ b/Resources/Locale/ru-RU/_backmen/store/uplink-catalog.ftl @@ -0,0 +1,3 @@ +uplink-experimental-syndicate-teleporter-name = Экспериментальный телепортер синдиката +uplink-experimental-syndicate-teleporter-desc = Телепортер синдиката, при использовании перемещает на 3-8 метров вперед. В случае телепортации в стену, использует экстренную телепортацию. Имеет 4 заряда и автоматически заряжается. + diff --git a/Resources/Prototypes/_Backmen/Catalog/uplink_catalog.yml b/Resources/Prototypes/_Backmen/Catalog/uplink_catalog.yml index eb374144e61..96db285f501 100644 --- a/Resources/Prototypes/_Backmen/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/_Backmen/Catalog/uplink_catalog.yml @@ -164,3 +164,12 @@ categories: - UplinkPointless +- type: listing + id: UplinkExperimentalSyndicateTeleporter + name: uplink-experimental-syndicate-teleporter-name + description: uplink-experimental-syndicate-teleporter-desc + productEntity: ExperimentalSyndicateTeleporter + cost: + Telecrystal: 10 + categories: + - UplinkDeception \ No newline at end of file diff --git a/Resources/Prototypes/_Backmen/Entities/Effects/effects.yml b/Resources/Prototypes/_Backmen/Entities/Effects/effects.yml new file mode 100644 index 00000000000..eb7dec23b78 --- /dev/null +++ b/Resources/Prototypes/_Backmen/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/Backmen/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/Backmen/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/_Backmen/Entities/Objects/Devices/Syndicate_Gadgets/experimental_teleporter.yml b/Resources/Prototypes/_Backmen/Entities/Objects/Devices/Syndicate_Gadgets/experimental_teleporter.yml new file mode 100644 index 00000000000..05668c3def8 --- /dev/null +++ b/Resources/Prototypes/_Backmen/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/Backmen/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/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png new file mode 100644 index 00000000000..106f3f415c8 Binary files /dev/null and b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/icon.png differ diff --git a/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png new file mode 100644 index 00000000000..456e592a332 Binary files /dev/null and b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/in.png differ diff --git a/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png new file mode 100644 index 00000000000..1b5ed5d0775 Binary files /dev/null and b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-left.png differ diff --git a/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png new file mode 100644 index 00000000000..ff383c03544 Binary files /dev/null and b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/inhand-right.png differ diff --git a/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/meta.json b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/meta.json new file mode 100644 index 00000000000..038ce06e4bc --- /dev/null +++ b/Resources/Textures/Backmen/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/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png new file mode 100644 index 00000000000..6483dbcc3bd Binary files /dev/null and b/Resources/Textures/Backmen/Objects/Devices/experimentalsyndicateteleporter.rsi/out.png differ