Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the bionic syrinx implant #339

Merged
merged 14 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -68,7 +68,8 @@ private void OnSpeakerNameTransform(EntityUid uid, VoiceMaskComponent component,

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 @@ -79,7 +80,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.
Loading