[Feature] Экспериментальный телепортер синдиката (#250)
* add: experimental syndicate teleporter * randomvector method * fix * check mob attempt 1 * revert * add check for pull * new charge system * changes * changes * small fix
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server._White.Other;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Pulling;
|
||||
using Content.Shared.Coordinates.Helpers;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Pulling.Components;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._White.ExperimentalSyndicateTeleporter;
|
||||
public sealed class ExperimentalSyndicateTeleporter : 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 IGameTiming _timing = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly PullingSystem _pullingSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ExperimentalSyndicateTeleporterComponent, UseInHandEvent>(OnUse);
|
||||
SubscribeLocalEvent<ExperimentalSyndicateTeleporterComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ExperimentalSyndicateTeleporterComponent>();
|
||||
while (query.MoveNext(out var component))
|
||||
{
|
||||
if (component.Uses >= 4)
|
||||
continue;
|
||||
|
||||
component.ChargeCooldown += _timing.FrameTime;
|
||||
|
||||
if (component.ChargeCooldown <= component.NextRechargeAttempt)
|
||||
continue;
|
||||
|
||||
if (_random.Next(0, 10) != 0)
|
||||
{
|
||||
component.ChargeCooldown = TimeSpan.Zero;
|
||||
continue;
|
||||
}
|
||||
|
||||
component.Uses++;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUse(EntityUid uid, ExperimentalSyndicateTeleporterComponent component, UseInHandEvent args)
|
||||
{
|
||||
if (component.Uses <= 0)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("experimental-syndicate-teleporter-end-uses"), args.User, args.User, PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.NextUse > _timing.CurTime)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("experimental-syndicate-teleporter-cooldown"), args.User, args.User, PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<TransformComponent>(args.User, out var xform))
|
||||
return;
|
||||
|
||||
if (TryComp<SharedPullableComponent>(args.User, out var pullable) && pullable.BeingPulled)
|
||||
{
|
||||
_pullingSystem.TryStopPull(pullable);
|
||||
}
|
||||
|
||||
if (TryComp<SharedPullerComponent>(args.User, out var pulling)
|
||||
&& pulling.Pulling != null &&
|
||||
TryComp<SharedPullableComponent>(pulling.Pulling.Value, out var subjectPulling))
|
||||
{
|
||||
_pullingSystem.TryStopPull(subjectPulling);
|
||||
}
|
||||
|
||||
var oldCoords = xform.Coordinates;
|
||||
|
||||
var random = _random.Next(component.MinTeleportRange, component.MaxTeleportRange);
|
||||
var offset = xform.LocalRotation.ToWorldVec().Normalized();
|
||||
var direction = xform.LocalRotation.GetDir().ToVec();
|
||||
var newOffset = offset + direction * random;
|
||||
|
||||
var coords = xform.Coordinates.Offset(newOffset).SnapToGrid(EntityManager);
|
||||
|
||||
if (TryCheckWall(coords))
|
||||
{
|
||||
EmergencyTeleportation(args.User, xform, component, oldCoords);
|
||||
return;
|
||||
}
|
||||
|
||||
SoundAndEffects(component, coords, oldCoords);
|
||||
|
||||
_transform.SetCoordinates(args.User, coords);
|
||||
|
||||
component.Uses--;
|
||||
component.NextUse = _timing.CurTime + component.Cooldown;
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, ExperimentalSyndicateTeleporterComponent component, ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("experimental-syndicate-teleporter-examine", ("uses", component.Uses)));
|
||||
}
|
||||
|
||||
private void EmergencyTeleportation(EntityUid uid, TransformComponent xform, ExperimentalSyndicateTeleporterComponent component, EntityCoordinates oldCoords)
|
||||
{
|
||||
var offset = xform.LocalRotation.ToWorldVec().Normalized();
|
||||
var newOffset = offset + VectorRandomDirection(component, offset, component.EmergencyLength);
|
||||
|
||||
var coords = xform.Coordinates.Offset(newOffset).SnapToGrid(EntityManager);
|
||||
|
||||
SoundAndEffects(component, coords, oldCoords);
|
||||
|
||||
_transform.SetCoordinates(uid, coords);
|
||||
|
||||
component.Uses--;
|
||||
component.NextUse = _timing.CurTime + component.Cooldown;
|
||||
|
||||
if (TryCheckWall(coords))
|
||||
{
|
||||
_bodySystem.GibBody(uid, true, splatModifier: 3F);
|
||||
}
|
||||
}
|
||||
|
||||
private void SoundAndEffects(ExperimentalSyndicateTeleporterComponent component, EntityCoordinates coords, EntityCoordinates oldCoords)
|
||||
{
|
||||
_audio.PlayPvs(component.TeleportSound, coords);
|
||||
_audio.PlayPvs(component.TeleportSound, oldCoords);
|
||||
|
||||
_entManager.SpawnEntity(component.ExpSyndicateTeleportInEffect, coords);
|
||||
_entManager.SpawnEntity(component.ExpSyndicateTeleportOutEffect, oldCoords);
|
||||
}
|
||||
|
||||
private bool TryCheckWall(EntityCoordinates coords)
|
||||
{
|
||||
if (!coords.TryGetTileRef(out var tile))
|
||||
return false;
|
||||
|
||||
if (!TryComp<MapGridComponent>(tile.Value.GridUid, out var mapGridComponent))
|
||||
return false;
|
||||
|
||||
var anchoredEntities = _mapSystem.GetAnchoredEntities(tile.Value.GridUid, mapGridComponent, coords);
|
||||
|
||||
return anchoredEntities.Any(HasComp<WallMarkComponent>);
|
||||
}
|
||||
|
||||
private Vector2 VectorRandomDirection(ExperimentalSyndicateTeleporterComponent component, Vector2 offset, int length)
|
||||
{
|
||||
var randomRotation = _random.Next(0, component.RandomRotations.Count);
|
||||
return Angle.FromDegrees(component.RandomRotations[randomRotation]).RotateVec(offset.Normalized() * length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._White.ExperimentalSyndicateTeleporter;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class ExperimentalSyndicateTeleporterComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int Uses = 4;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int MinTeleportRange = 3;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int MaxTeleportRange = 8;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int EmergencyLength = 3;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public List<int> RandomRotations = new() {90, -90};
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string? ExpSyndicateTeleportInEffect = "ExpSyndicateTeleporterInEffect";
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string? ExpSyndicateTeleportOutEffect = "ExpSyndicateTeleporterOutEffect";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/White/Devices/expsyndicateteleport.ogg");
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan Cooldown = TimeSpan.FromSeconds(5);
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public TimeSpan NextUse = TimeSpan.Zero;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public TimeSpan NextRechargeAttempt = TimeSpan.FromSeconds(1);
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public TimeSpan ChargeCooldown = TimeSpan.Zero;
|
||||
}
|
||||
BIN
Resources/Audio/White/Devices/expsyndicateteleport.ogg
Normal file
BIN
Resources/Audio/White/Devices/expsyndicateteleport.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
ent-ExperimentalSyndicateTeleporter = экспериментальный телепортер синдиката
|
||||
.desc = Телепортер синдиката, при использовании перемещает на 3-8 метров вперед. В случае телепортации в стену, использует экстренную телепортацию. Имеет 4 заряда и автоматически заряжается.
|
||||
experimental-syndicate-teleporter-examine = Доступные заряды телепортера: [color=fuchsia]{ $uses }[/color].
|
||||
experimental-syndicate-teleporter-end-uses = Заряды телепортера закончились!
|
||||
experimental-syndicate-teleporter-cooldown = Телепортер перезаряжается!
|
||||
|
||||
uplink-experimentalsyndicateteleporter = Экспериментальный телепортер синдиката
|
||||
uplink-experimentalsyndicateteleporter-desc = Телепортер синдиката, при использовании перемещает на 3-8 метров вперед. В случае телепортации в стену, использует экстренную телепортацию. Имеет 4 заряда и автоматически заряжается.
|
||||
@@ -250,3 +250,15 @@
|
||||
Telecrystal: 1
|
||||
categories:
|
||||
- UplinkImplants
|
||||
|
||||
- type: listing
|
||||
id: UplinkExperimentalSyndicateTeleporter
|
||||
name: uplink-experimentalsyndicateteleporter
|
||||
description: uplink-experimentalsyndicateteleporter-desc
|
||||
icon: { sprite: /Textures/White/Objects/Devices/experimentalsyndicateteleporter.rsi, state: icon }
|
||||
productEntity: ExperimentalSyndicateTeleporter
|
||||
cost:
|
||||
Telecrystal: 8
|
||||
categories:
|
||||
- UplinkUtility
|
||||
saleLimit: 2
|
||||
@@ -0,0 +1,51 @@
|
||||
- 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: ExperimentalSyndicateTeleporter
|
||||
|
||||
- type: entity
|
||||
id: ExpSyndicateTeleporterInEffect
|
||||
name: Experimental Syndicate Teleporter In Effect
|
||||
components:
|
||||
- type: TimedDespawn
|
||||
lifetime: 0.6
|
||||
- type: EvaporationSparkle
|
||||
- type: Transform
|
||||
noRot: true
|
||||
anchored: true
|
||||
- type: Sprite
|
||||
layers:
|
||||
- sprite: White/Objects/Devices/experimentalsyndicateteleporter.rsi
|
||||
state: in
|
||||
shader: unshaded
|
||||
netsync: false
|
||||
drawdepth: Effects
|
||||
- type: PointLight
|
||||
color: "#008DFE"
|
||||
|
||||
- type: entity
|
||||
id: ExpSyndicateTeleporterOutEffect
|
||||
name: Experimental Syndicate Teleporter Out Effect
|
||||
components:
|
||||
- type: TimedDespawn
|
||||
lifetime: 0.6
|
||||
- type: EvaporationSparkle
|
||||
- type: Transform
|
||||
noRot: true
|
||||
anchored: true
|
||||
- type: Sprite
|
||||
layers:
|
||||
- sprite: White/Objects/Devices/experimentalsyndicateteleporter.rsi
|
||||
state: out
|
||||
shader: unshaded
|
||||
netsync: false
|
||||
drawdepth: Effects
|
||||
- type: PointLight
|
||||
color: "#008DFE"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 409 B |
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 248 B |
Binary file not shown.
|
After Width: | Height: | Size: 247 B |
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Base sprite taken by tg station, 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
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Reference in New Issue
Block a user