forked from space-syndicate/space-station-14
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
518 additions
and
6 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
Content.Client/_CorvaxNext/Implants/Radio/RadioImplantSystem.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using Content.Shared._CorvaxNext.Implants.Radio; | ||
|
||
namespace Content.Client._CorvaxNext.Implants.Radio; | ||
|
||
/// <inheritdoc /> | ||
public sealed class RadioImplantSystem : SharedRadioImplantSystem | ||
{ | ||
} |
126 changes: 126 additions & 0 deletions
126
Content.Server/_CorvaxNext/Implants/Radio/RadioImplantSystem.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
using Content.Server.Chat.Systems; | ||
using Content.Server.Radio; | ||
using Content.Server.Radio.Components; | ||
using Content.Server.Radio.EntitySystems; | ||
using Content.Shared._CorvaxNext.Implants.Radio; | ||
using Content.Shared.Radio.Components; | ||
using Robust.Shared.Containers; | ||
using Robust.Shared.Network; | ||
using Robust.Shared.Player; | ||
|
||
namespace Content.Server._CorvaxNext.Implants.Radio; | ||
|
||
/// <inheritdoc /> | ||
public sealed class RadioImplantSystem : SharedRadioImplantSystem | ||
{ | ||
[Dependency] private readonly INetManager _netManager = default!; | ||
[Dependency] private readonly RadioSystem _radioSystem = default!; | ||
|
||
private EntityQuery<ActorComponent> _actorQuery; | ||
|
||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
SubscribeLocalEvent<RadioImplantComponent, MapInitEvent>(OnMapInit); | ||
SubscribeLocalEvent<RadioImplantComponent, EntInsertedIntoContainerMessage>(OnInsertEncryptionKey); | ||
SubscribeLocalEvent<RadioImplantComponent, EntRemovedFromContainerMessage>(OnRemoveEncryptionKey); | ||
SubscribeLocalEvent<RadioImplantComponent, RadioReceiveEvent>(OnRadioReceive); | ||
SubscribeLocalEvent<HasRadioImplantComponent, EntitySpokeEvent>(OnSpeak); | ||
_actorQuery = GetEntityQuery<ActorComponent>(); | ||
} | ||
|
||
/// <summary> | ||
/// Ensures implants with fixed channels work. | ||
/// </summary> | ||
private void OnMapInit(Entity<RadioImplantComponent> ent, ref MapInitEvent args) | ||
{ | ||
UpdateRadioReception(ent); | ||
} | ||
|
||
/// <summary> | ||
/// Handles the implantee's speech being forwarded onto the radio channel of the implant. | ||
/// </summary> | ||
private void OnSpeak(Entity<HasRadioImplantComponent> ent, ref EntitySpokeEvent args) | ||
{ | ||
// not a radio message, or already handled by another radio | ||
if (args.Channel is null) | ||
return; | ||
|
||
// does the implant have access to the channel the implantee is trying to speak on? | ||
if (ent.Comp.Implant is {} implant | ||
&& TryComp<RadioImplantComponent>(implant, out var radioImplantComponent) | ||
&& radioImplantComponent.Channels.Contains(args.Channel.ID)) | ||
{ | ||
_radioSystem.SendRadioMessage(ent, args.Message, args.Channel.ID, implant); | ||
// prevent other radios they might be wearing from sending the message again | ||
args.Channel = null; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Handles receiving radio messages and forwarding them to the implantee. | ||
/// </summary> | ||
private void OnRadioReceive(EntityUid uid, RadioImplantComponent component, ref RadioReceiveEvent args) | ||
{ | ||
if (_actorQuery.TryComp(component.Implantee, out var actorComponent)) | ||
_netManager.ServerSendMessage(args.ChatMsg, actorComponent.PlayerSession.Channel); | ||
} | ||
|
||
/// <summary> | ||
/// Handles the addition of an encryption key to the implant's storage. | ||
/// </summary> | ||
private void OnInsertEncryptionKey(Entity<RadioImplantComponent> ent, ref EntInsertedIntoContainerMessage args) | ||
{ | ||
// check if the insertion is actually something getting inserted into the radio implant storage, since | ||
// this evt also fires when the radio implant is being inserted into a person. | ||
if (ent.Owner != args.Container.Owner | ||
|| !TryComp<EncryptionKeyComponent>(args.Entity, out var encryptionKeyComponent)) | ||
return; | ||
|
||
// copy over the radio channels that can be accessed | ||
ent.Comp.Channels.Clear(); | ||
foreach (var channel in encryptionKeyComponent.Channels) | ||
{ | ||
ent.Comp.Channels.Add(channel); | ||
} | ||
Dirty(ent); | ||
UpdateRadioReception(ent); | ||
} | ||
|
||
/// <summary> | ||
/// Handles the removal of an encryption key from the implant's storage. | ||
/// </summary> | ||
private void OnRemoveEncryptionKey(Entity<RadioImplantComponent> ent, ref EntRemovedFromContainerMessage args) | ||
{ | ||
// check if the insertion is actually something getting inserted into the radio implant storage, since | ||
// this evt also fires when the radio implant is being inserted into a person. | ||
if (ent.Owner != args.Container.Owner | ||
|| !HasComp<EncryptionKeyComponent>(args.Entity)) | ||
return; | ||
|
||
// clear the radio channels since there's no encryption key inserted anymore. | ||
ent.Comp.Channels.Clear(); | ||
Dirty(ent); | ||
UpdateRadioReception(ent); | ||
} | ||
|
||
/// <summary> | ||
/// Ensures that this thing can actually hear radio messages from channels the key provides. | ||
/// </summary> | ||
private void UpdateRadioReception(Entity<RadioImplantComponent> ent) | ||
{ | ||
if (ent.Comp.Channels.Count != 0) | ||
{ | ||
// we need to add this comp to actually receive radio events. | ||
var channels = EnsureComp<ActiveRadioComponent>(ent).Channels; | ||
foreach (var channel in ent.Comp.Channels) | ||
{ | ||
channels.Add(channel); | ||
} | ||
} | ||
else | ||
{ | ||
RemComp<ActiveRadioComponent>(ent); | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
Content.Server/_CorvaxNext/Storage/EntitySystems/MouthStorageSystem.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Content.Server.Nutrition; | ||
using Content.Server.Speech; | ||
using Content.Server.Speech.EntitySystems; | ||
using Content.Shared._CorvaxNext.Storage.Components; | ||
using Content.Shared._CorvaxNext.Storage.EntitySystems; | ||
using Content.Shared.Storage; | ||
|
||
namespace Content.Server._CorvaxNext.Storage.EntitySystems; | ||
|
||
public sealed class MouthStorageSystem : SharedMouthStorageSystem | ||
{ | ||
[Dependency] private readonly ReplacementAccentSystem _replacement = default!; | ||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
|
||
SubscribeLocalEvent<MouthStorageComponent, AccentGetEvent>(OnAccent); | ||
SubscribeLocalEvent<MouthStorageComponent, IngestionAttemptEvent>(OnIngestAttempt); | ||
} | ||
|
||
// Force you to mumble if you have items in your mouth | ||
private void OnAccent(EntityUid uid, MouthStorageComponent component, AccentGetEvent args) | ||
{ | ||
if (IsMouthBlocked(component)) | ||
args.Message = _replacement.ApplyReplacements(args.Message, "mumble"); | ||
} | ||
|
||
// Attempting to eat or drink anything with items in your mouth won't work | ||
private void OnIngestAttempt(EntityUid uid, MouthStorageComponent component, IngestionAttemptEvent args) | ||
{ | ||
if (!IsMouthBlocked(component)) | ||
return; | ||
|
||
if (!TryComp<StorageComponent>(component.MouthId, out var storage)) | ||
return; | ||
|
||
var firstItem = storage.Container.ContainedEntities[0]; | ||
args.Blocker = firstItem; | ||
args.Cancel(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
Content.Shared/_CorvaxNext/Implants/Radio/HasRadioImplantComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using Robust.Shared.GameStates; | ||
|
||
namespace Content.Shared._CorvaxNext.Implants.Radio; | ||
|
||
/// <summary> | ||
/// This indicates this entity has a radio implant implanted into themselves. | ||
/// </summary> | ||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedRadioImplantSystem))] | ||
public sealed partial class HasRadioImplantComponent : Component | ||
{ | ||
/// <summary> | ||
/// The radio implant. We need this to be able to determine encryption keys. | ||
/// </summary> | ||
[DataField, AutoNetworkedField] | ||
public EntityUid? Implant; | ||
} |
24 changes: 24 additions & 0 deletions
24
Content.Shared/_CorvaxNext/Implants/Radio/RadioImplantComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using Content.Shared.Radio; | ||
using Robust.Shared.GameStates; | ||
using Robust.Shared.Prototypes; | ||
|
||
namespace Content.Shared._CorvaxNext.Implants.Radio; | ||
|
||
/// <summary> | ||
/// This is for radio implants. Might be Syndie, might not be Syndie, but either way, it's an implant. | ||
/// </summary> | ||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedRadioImplantSystem))] | ||
public sealed partial class RadioImplantComponent : Component | ||
{ | ||
/// <summary> | ||
/// The entity this implant got added to. | ||
/// </summary> | ||
[DataField, AutoNetworkedField] | ||
public EntityUid? Implantee; | ||
|
||
/// <summary> | ||
/// The channels this implant can talk on. | ||
/// </summary> | ||
[DataField, AutoNetworkedField] | ||
public HashSet<ProtoId<RadioChannelPrototype>> Channels = new(); | ||
} |
56 changes: 56 additions & 0 deletions
56
Content.Shared/_CorvaxNext/Implants/Radio/SharedRadioImplantSystem.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using Content.Shared.Actions; | ||
using Content.Shared.Implants; | ||
using Content.Shared.Storage; | ||
using Content.Shared.Storage.EntitySystems; | ||
using Robust.Shared.Containers; | ||
|
||
namespace Content.Shared._CorvaxNext.Implants.Radio; | ||
|
||
/// <summary> | ||
/// This handles radio implants, which you can implant to get access to a radio channel. | ||
/// </summary> | ||
public abstract class SharedRadioImplantSystem : EntitySystem | ||
{ | ||
/// <inheritdoc/> | ||
public override void Initialize() | ||
{ | ||
SubscribeLocalEvent<RadioImplantComponent, ImplantImplantedEvent>(OnImplanted); | ||
SubscribeLocalEvent<RadioImplantComponent, EntGotRemovedFromContainerMessage>(OnPossiblyUnimplanted); | ||
} | ||
|
||
/// <summary> | ||
/// Handles implantation of the implant. | ||
/// </summary> | ||
private void OnImplanted(EntityUid uid, RadioImplantComponent component, ImplantImplantedEvent args) | ||
{ | ||
if (args.Implanted is not { Valid: true }) | ||
return; | ||
|
||
component.Implantee = args.Implanted.Value; | ||
Dirty(uid, component); | ||
|
||
// make sure the person entity gets slapped with a component so it can react to it talking. | ||
var hasRadioImplantComponent = EnsureComp<HasRadioImplantComponent>(args.Implanted.Value); | ||
hasRadioImplantComponent.Implant = uid; | ||
Dirty(component.Implantee.Value, hasRadioImplantComponent); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Handles removal of the implant from its containing mob. | ||
/// </summary> | ||
/// <remarks>Done via <see cref="EntGotRemovedFromContainerMessage"/> because there is no specific event for an implant being removed.</remarks> | ||
private void OnPossiblyUnimplanted(EntityUid uid, RadioImplantComponent component, EntGotRemovedFromContainerMessage args) | ||
{ | ||
if (Terminating(uid)) | ||
return; | ||
|
||
// this gets fired if it gets removed from ANY container but really, we just want to know if it was removed from its owner... | ||
// so check if the ent we got implanted into matches the container's owner (here, the container's owner is the entity) | ||
if (component.Implantee is not null && component.Implantee == args.Container.Owner) | ||
{ | ||
RemComp<HasRadioImplantComponent>(component.Implantee.Value); | ||
component.Implantee = null; | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
Content.Shared/_CorvaxNext/Storage/Components/MouthStorageComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using Content.Shared._CorvaxNext.Storage.EntitySystems; | ||
using Content.Shared.FixedPoint; | ||
using Robust.Shared.Containers; | ||
using Robust.Shared.GameStates; | ||
using Robust.Shared.Prototypes; | ||
namespace Content.Shared._CorvaxNext.Storage.Components; | ||
|
||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] | ||
[Access(typeof(SharedMouthStorageSystem))] | ||
public sealed partial class MouthStorageComponent : Component | ||
{ | ||
public const string MouthContainerId = "mouth"; | ||
|
||
[DataField, AutoNetworkedField] | ||
public EntProtoId? OpenStorageAction; | ||
|
||
[DataField, AutoNetworkedField] | ||
public EntityUid? Action; | ||
|
||
[DataField] | ||
public EntProtoId MouthProto = "ActionOpenMouthStorage"; | ||
|
||
[ViewVariables] | ||
public Container Mouth = default!; | ||
|
||
[DataField] | ||
public EntityUid? MouthId; | ||
|
||
// Mimimum inflicted damage on hit to spit out items | ||
[DataField] | ||
public FixedPoint2 SpitDamageThreshold = FixedPoint2.New(2); | ||
} |
Oops, something went wrong.