Skip to content

Commit

Permalink
Add the bionic syrinx implant (DeltaV-Station#339)
Browse files Browse the repository at this point in the history
* Add the bionic syrinx implant

* Make syrinx implant nonfunctional for non-harpies

* Deconflict syrinx with voice mask

* Don't allow non-harpies to inject a bionic syrinx

* Use the new implant whitelist for syrinx instead

* Add an action icon to the syrinx voicemask

* Remove now-obsolete syrinx implant error messages

* Move syrinx popups to player and to clientside

(cherry picked from commit 7b0c061)
  • Loading branch information
luringens authored and DebugOk committed Jan 20, 2024
1 parent 230ecad commit 43133a2
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 2 deletions.
113 changes: 113 additions & 0 deletions Content.Server/DeltaV/Implants/SubdermalBionicSyrinxImplantSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using Content.Server.Administration.Logs;
using Content.Server.Chat.Systems;
using Content.Server.Popups;
using Content.Server.VoiceMask;
using Content.Shared.Database;
using Content.Shared.Implants;
using Content.Shared.Implants.Components;
using Content.Shared.Popups;
using Content.Shared.Preferences;
using Content.Shared.Tag;
using Content.Shared.VoiceMask;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;

namespace Content.Server.Implants;

public sealed class SubdermalBionicSyrinxImplantSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly TagSystem _tag = default!;

[ValidatePrototypeId<TagPrototype>]
public const string BionicSyrinxImplant = "BionicSyrinxImplant";


public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<VoiceMaskerComponent, ImplantImplantedEvent>(OnInsert);
SubscribeLocalEvent<SyrinxVoiceMaskComponent, TransformSpeakerNameEvent>(OnSpeakerNameTransform);
SubscribeLocalEvent<SyrinxVoiceMaskComponent, VoiceMaskChangeNameMessage>(OnChangeName);
// We need to remove the SyrinxVoiceMaskComponent from the owner before the implant
// is removed, so we need to execute before the SubdermalImplantSystem.
SubscribeLocalEvent<VoiceMaskerComponent, EntGotRemovedFromContainerMessage>(OnRemove, before: new[] { typeof(SubdermalImplantSystem) });
}

private void OnInsert(EntityUid uid, VoiceMaskerComponent component, ImplantImplantedEvent args)
{
if (!args.Implanted.HasValue ||
!_tag.HasTag(args.Implant, BionicSyrinxImplant))
return;

var voicemask = EnsureComp<SyrinxVoiceMaskComponent>(args.Implanted.Value);
voicemask.VoiceName = MetaData(args.Implanted.Value).EntityName;
Dirty(args.Implanted.Value, voicemask);
}

private void OnRemove(EntityUid uid, VoiceMaskerComponent component, EntGotRemovedFromContainerMessage args)
{
if (!TryComp<SubdermalImplantComponent>(uid, out var implanted) || implanted.ImplantedEntity == null)
return;

RemComp<SyrinxVoiceMaskComponent>(implanted.ImplantedEntity.Value);
}

/// <summary>
/// Copy from VoiceMaskSystem, adapted to work with SyrinxVoiceMaskComponent.
/// </summary>
private void OnChangeName(EntityUid uid, SyrinxVoiceMaskComponent component, VoiceMaskChangeNameMessage message)
{
if (message.Name.Length > HumanoidCharacterProfile.MaxNameLength || message.Name.Length <= 0)
{
_popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-failure"), uid, message.Session, PopupType.SmallCaution);
return;
}

component.VoiceName = message.Name;
if (message.Session.AttachedEntity != null)
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} set voice of {ToPrettyString(uid):mask}: {component.VoiceName}");
else
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"Voice of {ToPrettyString(uid):mask} set: {component.VoiceName}");

_popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), uid, message.Session);
TrySetLastKnownName(uid, message.Name);
UpdateUI(uid, component);
}

/// <summary>
/// Copy from VoiceMaskSystem, adapted to work with SyrinxVoiceMaskComponent.
/// </summary>
private void TrySetLastKnownName(EntityUid implanted, string lastName)
{
if (!HasComp<VoiceMaskComponent>(implanted)
|| !TryComp<VoiceMaskerComponent>(implanted, out var maskComp))
return;

maskComp.LastSetName = lastName;
}

/// <summary>
/// Copy from VoiceMaskSystem, adapted to work with SyrinxVoiceMaskComponent.
/// </summary>
private void UpdateUI(EntityUid owner, SyrinxVoiceMaskComponent? component = null)
{
if (!Resolve(owner, ref component, logMissing: false))
return;

if (_uiSystem.TryGetUi(owner, VoiceMaskUIKey.Key, out var bui))
_uiSystem.SetUiState(bui, new VoiceMaskBuiState(component.VoiceName));
}

/// <summary>
/// Copy from VoiceMaskSystem, adapted to work with SyrinxVoiceMaskComponent.
/// </summary>
private void OnSpeakerNameTransform(EntityUid uid, SyrinxVoiceMaskComponent component, TransformSpeakerNameEvent args)
{
if (component.Enabled)
args.Name = component.VoiceName;
}
}
9 changes: 9 additions & 0 deletions Content.Server/DeltaV/VoiceMask/SyrinxVoiceMaskComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Content.Server.VoiceMask;

[RegisterComponent]
public sealed partial class SyrinxVoiceMaskComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)] public bool Enabled = true;

[ViewVariables(VVAccess.ReadWrite)] public string VoiceName = "Unknown";
}
6 changes: 4 additions & 2 deletions Content.Server/VoiceMask/VoiceMaskSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ private void OnMaskToggled(Entity<VoiceMaskComponent> ent, ref WearerMaskToggled

private void OpenUI(EntityUid player, ActorComponent? actor = null)
{
if (!Resolve(player, ref actor))
// Delta-V: `logMissing: false` because of syrinx.
if (!Resolve(player, ref actor, logMissing: false))
return;
if (!_uiSystem.TryGetUi(player, VoiceMaskUIKey.Key, out var bui))
return;
Expand All @@ -87,7 +88,8 @@ private void OpenUI(EntityUid player, ActorComponent? actor = null)

private void UpdateUI(EntityUid owner, VoiceMaskComponent? component = null)
{
if (!Resolve(owner, ref component))
// Delta-V: `logMissing: false` because of syrinx
if (!Resolve(owner, ref component, logMissing: false))
{
return;
}
Expand Down
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/deltav/store/uplink-catalog.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
uplink-bionic-syrinx-implanter-name = Bionic Syrinx Implanter
uplink-bionic-syrinx-implanter-desc = An implant that enhances a harpy's natural talent for mimicry to let you adjust your voice to whoever you can think of.
14 changes: 14 additions & 0 deletions Resources/Prototypes/DeltaV/Catalog/uplink_catalog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,17 @@
# blacklist:
# components:
# - SurplusBundle

- type: listing
id: UplinkBionicSyrinxImplanter
name: uplink-bionic-syrinx-implanter-name
description: uplink-bionic-syrinx-implanter-desc
productEntity: BionicSyrinxImplanter
cost:
Telecrystal: 2
categories:
- UplinkImplants
conditions:
- !type:BuyerSpeciesCondition
whitelist:
- Harpy
11 changes: 11 additions & 0 deletions Resources/Prototypes/DeltaV/Entities/Mobs/Species/harpy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,14 @@
icon: DeltaV/Interface/Actions/harpy_sing.png
event: !type:OpenUiActionEvent
key: enum.InstrumentUiKey.Key

- type: entity
id: ActionSyrinxChangeVoiceMask
name: Set name
description: Change the name others hear to something else.
noSpawn: true
components:
- type: InstantAction
icon: DeltaV/Interface/Actions/harpy_syrinx.png
itemIconStyle: BigAction
event: !type:VoiceMaskSetNameEvent
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- type: entity
id: BionicSyrinxImplanter
name: bionic syrinx implanter
parent: BaseImplantOnlyImplanterSyndi
components:
- type: Implanter
implant: BionicSyrinxImplant
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
- type: entity
parent: BaseSubdermalImplant
id: BionicSyrinxImplant
name: bionic syrinx implant
description: This implant lets a harpy adjust their voice to whoever they can think of.
noSpawn: true
components:
- type: SubdermalImplant
implantAction: ActionSyrinxChangeVoiceMask
whitelist:
components:
- HarpySinger
- type: VoiceMasker
- type: Tag
tags:
- SubdermalImplant
- BionicSyrinxImplant
3 changes: 3 additions & 0 deletions Resources/Prototypes/DeltaV/tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@

- type: Tag
id: PreventLabel

- type: Tag
id: BionicSyrinxImplant
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 43133a2

Please sign in to comment.