forked from space-wizards/space-station-14
-
Notifications
You must be signed in to change notification settings - Fork 161
/
Copy pathSubdermalImplantSystem.cs
190 lines (155 loc) · 7.57 KB
/
SubdermalImplantSystem.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
using Content.Server.Actions;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Cuffs;
using Content.Server.Forensics;
using Content.Server.Humanoid;
using Content.Server.Implants.Components;
using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Cuffs.Components;
using Content.Shared.Humanoid;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
using Content.Shared.Interaction;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Preferences;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
namespace Content.Server.Implants;
public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
{
[Dependency] private readonly CuffableSystem _cuffable = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
public override void Initialize()
{
base.Initialize();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<SubdermalImplantComponent, UseChemicalImplantEvent>(OnChemicaImplant); // SS220 - chemical-implants start
SubscribeLocalEvent<SubdermalImplantComponent, UseFreedomImplantEvent>(OnFreedomImplant);
SubscribeLocalEvent<StoreComponent, ImplantRelayEvent<AfterInteractUsingEvent>>(OnStoreRelay);
SubscribeLocalEvent<SubdermalImplantComponent, ActivateImplantEvent>(OnActivateImplantEvent);
SubscribeLocalEvent<SubdermalImplantComponent, UseScramImplantEvent>(OnScramImplant);
SubscribeLocalEvent<SubdermalImplantComponent, UseDnaScramblerImplantEvent>(OnDnaScramblerImplant);
}
// SS220 - chemical-implants start
private void OnChemicaImplant(EntityUid uid, SubdermalImplantComponent component, UseChemicalImplantEvent args)
{
if (component.ImplantedEntity is not { } ent)
return;
if (!TryComp<SolutionContainerManagerComponent>(args.Performer, out var _performerSolutionComp)
|| !TryComp<SolutionContainerManagerComponent>(uid, out var _implantSolutionComp))
return;
if (!_solutionContainer.TryGetSolution(new(args.Performer, _performerSolutionComp), "chemicals", out var chemicalSolution))
return;
if (!_solutionContainer.TryGetSolution(new(uid, _implantSolutionComp), "beaker", out var beakerSolution))
return;
_solutionContainer.TryTransferSolution(chemicalSolution.Value, beakerSolution.Value.Comp.Solution, beakerSolution.Value.Comp.Solution.Volume);
args.Handled = true;
QueueDel(uid);
}
// SS220 - chemical-implants end
private void OnStoreRelay(EntityUid uid, StoreComponent store, ImplantRelayEvent<AfterInteractUsingEvent> implantRelay)
{
var args = implantRelay.Event;
if (args.Handled)
return;
// can only insert into yourself to prevent uplink checking with renault
if (args.Target != args.User)
return;
if (!TryComp<CurrencyComponent>(args.Used, out var currency))
return;
// same as store code, but message is only shown to yourself
args.Handled = _store.TryAddCurrency(_store.GetCurrencyValue(args.Used, currency), uid, store);
if (!args.Handled)
return;
var msg = Loc.GetString("store-currency-inserted-implant", ("used", args.Used));
_popup.PopupEntity(msg, args.User, args.User);
QueueDel(args.Used);
}
private void OnFreedomImplant(EntityUid uid, SubdermalImplantComponent component, UseFreedomImplantEvent args)
{
if (!TryComp<CuffableComponent>(component.ImplantedEntity, out var cuffs) || cuffs.Container.ContainedEntities.Count < 1)
return;
_cuffable.Uncuff(component.ImplantedEntity.Value, cuffs.LastAddedCuffs, cuffs.LastAddedCuffs);
args.Handled = true;
}
private void OnActivateImplantEvent(EntityUid uid, SubdermalImplantComponent component, ActivateImplantEvent args)
{
args.Handled = true;
}
private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, UseScramImplantEvent args)
{
if (component.ImplantedEntity is not { } ent)
return;
if (!TryComp<ScramImplantComponent>(uid, out var implant))
return;
var xform = Transform(ent);
var entityCoords = xform.Coordinates.ToMap(EntityManager);
// try to find a valid position to teleport to, teleport to whatever works if we can't
var targetCoords = new MapCoordinates();
for (var i = 0; i < implant.TeleportAttempts; i++)
{
var distance = implant.TeleportRadius * MathF.Sqrt(_random.NextFloat()); // to get an uniform distribution
targetCoords = entityCoords.Offset(_random.NextAngle().ToVec() * distance);
// prefer teleporting to grids
if (!_mapManager.TryFindGridAt(targetCoords, out var gridUid, out var grid))
continue;
// the implant user probably does not want to be in your walls
var valid = true;
foreach (var entity in grid.GetAnchoredEntities(targetCoords))
{
if (!_physicsQuery.TryGetComponent(entity, out var body))
continue;
if (body.BodyType != BodyType.Static ||
!body.Hard ||
(body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
continue;
valid = false;
break;
}
if (valid)
break;
}
_xform.SetWorldPosition(ent, targetCoords.Position);
_xform.AttachToGridOrMap(ent, xform);
_audio.PlayPvs(implant.TeleportSound, ent);
args.Handled = true;
}
private void OnDnaScramblerImplant(EntityUid uid, SubdermalImplantComponent component, UseDnaScramblerImplantEvent args)
{
if (component.ImplantedEntity is not { } ent)
return;
if (TryComp<HumanoidAppearanceComponent>(ent, out var humanoid))
{
var newProfile = HumanoidCharacterProfile.RandomWithSpecies(humanoid.Species);
_humanoidAppearance.LoadProfile(ent, newProfile, humanoid);
_metaData.SetEntityName(ent, newProfile.Name);
if (TryComp<DnaComponent>(ent, out var dna))
{
dna.DNA = _forensicsSystem.GenerateDNA();
}
if (TryComp<FingerprintComponent>(ent, out var fingerprint))
{
fingerprint.Fingerprint = _forensicsSystem.GenerateFingerprint();
}
_popup.PopupEntity(Loc.GetString("scramble-implant-activated-popup"), ent, ent);
}
args.Handled = true;
QueueDel(uid);
}
}