Новый трейт: мурлыкание (#2624)

This commit is contained in:
iertis 2025-07-31 23:14:44 +05:00 committed by ReWAFFlution
parent 16dc995a18
commit 3d83063b52
5 changed files with 118 additions and 1 deletions

View file

@ -0,0 +1,23 @@
using Content.Shared.Chat.Prototypes;
using Content.Shared.Humanoid;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
namespace Content.Server._Sunrise.ReplacementVocal;
/// <summary>
/// Компонент для замены вокальных звуков и эмоций сущности.
/// Сохраняет предыдущие настройки для возможности восстановления.
/// </summary>
[RegisterComponent]
public sealed partial class ReplacementVocalComponent : Component
{
[DataField(customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer<Sex, EmoteSoundsPrototype>), required: true)]
public Dictionary<Sex, string> Vocal;
[DataField]
public HashSet<string> AddedEmotes = new();
[DataField(customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer<Sex, EmoteSoundsPrototype>))]
public Dictionary<Sex, string>? PreviousVocal;
}

View file

@ -0,0 +1,72 @@
using Content.Shared.Humanoid;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;
using Robust.Shared.Prototypes;
namespace Content.Server._Sunrise.ReplacementVocal;
public sealed class ReplacementVocalSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
SubscribeLocalEvent<ReplacementVocalComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<ReplacementVocalComponent, ComponentShutdown>(OnComponentShutdown);
}
private void OnComponentInit(EntityUid uid, ReplacementVocalComponent component, ComponentInit args)
{
if (!TryComp<VocalComponent>(uid, out var vocalComponent))
return;
if (component.Vocal.Keys == vocalComponent.Sounds?.Keys)
return;
if (!TryComp<SpeechComponent>(uid, out var speechComponent))
return;
component.PreviousVocal = vocalComponent.Sounds;
vocalComponent.Sounds = component.Vocal;
LoadEmotes(uid, vocalComponent);
foreach (var emote in vocalComponent.EmoteSounds!.Sounds.Keys)
{
if (speechComponent.AllowedEmotes.Contains(emote))
continue;
speechComponent.AllowedEmotes.Add(emote);
component.AddedEmotes.Add(emote);
}
}
private void OnComponentShutdown(EntityUid uid, ReplacementVocalComponent component, ComponentShutdown args)
{
if (!TryComp<SpeechComponent>(uid, out var speech))
return;
if (!TryComp<VocalComponent>(uid, out var vocal))
return;
if (component.PreviousVocal != null)
vocal.Sounds = component.PreviousVocal;
LoadEmotes(uid, vocal);
foreach (var emote in component.AddedEmotes)
{
speech.AllowedEmotes.Remove(emote);
}
component.AddedEmotes.Clear();
}
private void LoadEmotes(EntityUid uid, VocalComponent vocalComponent)
{
var sex = CompOrNull<HumanoidAppearanceComponent>(uid)?.Sex ?? Sex.Unsexed;
if (vocalComponent.Sounds?.TryGetValue(sex, out var protoId) == true)
_proto.TryIndex(protoId, out vocalComponent.EmoteSounds);
}
}

View file

@ -1,3 +1,5 @@
trait-category-height = Рост
trait-category-vocal = Голос
trait-colorblindness-name = Дальтонизм
trait-colorblindness-desc = Вы видите мир не так, как все.
trait-OwOAccent-name = акцент OwO
@ -16,4 +18,5 @@ trait-tall-quirk-name = высокий
trait-tall-quirk-desc = Делает вас немного выше (Только визуально!).
trait-short-quirk-name = низкий
trait-short-quirk-desc = Делает вас немного ниже (Только визуально!).
trait-category-height = Рост
trait-felinid-vocal-name = мурлыкание
trait-felinid-vocal-desc = Заменяет ваши звуки эмоций фелинидскими. Ня!

View file

@ -2,3 +2,9 @@
id: HeightTraits
name: trait-category-height
maxTraitPoints: 1
- type: traitCategory
id: VocalTraits
name: trait-category-vocal
maxTraitPoints: 1

View file

@ -25,3 +25,16 @@
components:
- type: RescaleSprite
scale: 1,0.9
- type: trait
id: FelinidVocal
name: trait-felinid-vocal-name
description: trait-felinid-vocal-desc
category: VocalTraits
cost: 1
components:
- type: ReplacementVocal
vocal:
Male: MaleFelinid
Female: FemaleFelinid
Unsexed: MaleFelinid