mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
Refactor voice to separate it from sex (#40593)
* feat: separate sex from voice
* wip: tried to make it use voice collection directly
* fix: yaml
* fix: migrations
* fix: ensure valid now validates correctly
* fix: unisex mobs wouldn't have voice
* chore: fix RT version
* refactor: clean up code into subfunctions
* refactor: swap name and protoId in voice
also rename sounds to voice
* chore: add comment
* fix: fallback sounds for non-humanoid characters
* fix: tests
* fix: tests
* refactor: change requests
* refactor: convert sheepers
* refactor: move Voice to SpeciesPrototype
* chore: add tests
* fix: test IoC error
* refactor: use null coalesing in ConvertProfiles
* refactor: move vocal sex association to speciesPrototype
* style: remove space from new()
* refactor: use name from emoteSoundsPrototype for UI
* refactor: no more null Voice on profile
* refactor: make DefaultVoice a static readonly property
* fix: add default voice to HumanoidProfileComponent
* chore: remove repeated vocal component from species yaml
It's inherited from BaseSpeciesMob
* style: correct comments for refactor
* fix: add missing locale for FemaleVulpkanin
* refactor: simplify logic based off surounding code
* test: add test to make sure that sexes are properly enumerated for the voices
* fix: add back urist sounds
* style: clarify comments again
* style: last thing im changing before I sleep
* refactor: battling programming semantics
* refactor: Name on EmoteSoundsPrototype.cs to VoiceSelectorName for clarity
* revert: isDirty change
* Fix HumanoidProfileTest.EnsureValidLoading.
The profile's voice wasnt being updated, thus the voiceChanged event was never raised and that meant that the voice component had old EmoteSounds
* oops
* refactor: do the easy change requests
* refactor: use an array for indexing sex conversion for performance
* fix master
* mistakes were made
* chore: redo migrations
---------
Co-authored-by: AJCM-git <ajcm_mail@disroot.org>
This commit is contained in:
parent
e24d755c33
commit
9805fe3956
52 changed files with 4773 additions and 160 deletions
|
|
@ -1,9 +1,11 @@
|
|||
using System.Linq;
|
||||
using Content.Client.UserInterface.Systems.Guidebook;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Speech.Components;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
|
@ -16,6 +18,7 @@ public sealed partial class HumanoidProfileEditor
|
|||
|
||||
private ColorSelectorSliders _rgbSkinColorSelector;
|
||||
private List<SpeciesPrototype> _species = new();
|
||||
private List<EmoteSoundsPrototype> _voices = new();
|
||||
private static readonly ProtoId<GuideEntryPrototype> DefaultSpeciesGuidebook = "Species";
|
||||
|
||||
public void UpdateSpeciesGuidebookIcon()
|
||||
|
|
@ -97,6 +100,34 @@ public sealed partial class HumanoidProfileEditor
|
|||
EyeColorPicker.SetData(Profile.Appearance.EyeColor);
|
||||
}
|
||||
|
||||
private void UpdateVoiceControls()
|
||||
{
|
||||
if (Profile == null)
|
||||
return;
|
||||
|
||||
VoiceButton.Clear();
|
||||
_voices.Clear();
|
||||
|
||||
var speciesPrototype = _prototypeManager.Index(Profile.Species);
|
||||
var availableVoices = speciesPrototype.Voices;
|
||||
|
||||
_voices.AddRange(availableVoices.Select(protoId => _prototypeManager.Index(protoId)));
|
||||
|
||||
if (_voices.All(proto => Profile?.Voice != proto.ID))
|
||||
SetVoice(speciesPrototype.DefaultSoundsBySex[(int)Profile.Sex]);
|
||||
|
||||
for (var i = 0; i < availableVoices.Count; i++)
|
||||
{
|
||||
var name = Loc.GetString(_voices[i].VoiceSelectorName);
|
||||
VoiceButton.AddItem(name, i);
|
||||
|
||||
if (Profile?.Voice.Equals(_voices[i].ID) == true)
|
||||
{
|
||||
VoiceButton.SelectId(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSkinColor()
|
||||
{
|
||||
if (Profile == null)
|
||||
|
|
@ -188,6 +219,7 @@ public sealed partial class HumanoidProfileEditor
|
|||
// In case there's species restrictions for loadouts
|
||||
RefreshLoadouts();
|
||||
UpdateSexControls(); // update sex for new species
|
||||
UpdateVoiceControls();
|
||||
UpdateSpeciesGuidebookIcon();
|
||||
ReloadPreview();
|
||||
}
|
||||
|
|
@ -215,11 +247,22 @@ public sealed partial class HumanoidProfileEditor
|
|||
break;
|
||||
}
|
||||
|
||||
// this does the same as above but for voice
|
||||
if (_prototypeManager.TryIndex(Profile?.Species, out var prototype))
|
||||
SetVoice(prototype.DefaultSoundsBySex[(int)newSex]);
|
||||
|
||||
UpdateGenderControls();
|
||||
UpdateVoiceControls();
|
||||
_markingsModel.SetOrganSexes(newSex);
|
||||
ReloadPreview();
|
||||
}
|
||||
|
||||
private void SetVoice(ProtoId<EmoteSoundsPrototype> newVoice)
|
||||
{
|
||||
Profile = Profile?.WithVoice(newVoice);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
private void SetGender(Gender newGender)
|
||||
{
|
||||
Profile = Profile?.WithGender(newGender);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@
|
|||
<Control HorizontalExpand="True"/>
|
||||
<OptionButton Name="SexButton" HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
<!-- Voice -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Text="{Loc 'humanoid-profile-editor-voice-label'}" />
|
||||
<Control HorizontalExpand="True" />
|
||||
<OptionButton Name="VoiceButton" HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
<!-- Pronouns -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Text="{Loc 'humanoid-profile-editor-pronouns-label'}" />
|
||||
|
|
|
|||
|
|
@ -164,6 +164,16 @@ namespace Content.Client.Lobby.UI
|
|||
|
||||
#endregion Sex
|
||||
|
||||
#region Voice
|
||||
|
||||
VoiceButton.OnItemSelected += args =>
|
||||
{
|
||||
VoiceButton.SelectId(args.Id);
|
||||
SetVoice(_voices[args.Id]);
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Age
|
||||
|
||||
AgeEdit.OnTextChanged += args =>
|
||||
|
|
@ -369,6 +379,7 @@ namespace Content.Client.Lobby.UI
|
|||
UpdateNameEdit();
|
||||
UpdateFlavorTextEdit();
|
||||
UpdateSexControls();
|
||||
UpdateVoiceControls();
|
||||
UpdateGenderControls();
|
||||
UpdateSkinColor();
|
||||
UpdateSpawnPriorityControls();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq;
|
||||
using Content.IntegrationTests.Fixtures;
|
||||
using Content.IntegrationTests.Fixtures.Attributes;
|
||||
using Content.IntegrationTests.Utility;
|
||||
using Content.Shared.Body;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
|
|
@ -20,7 +21,9 @@ namespace Content.IntegrationTests.Tests.Humanoid;
|
|||
public sealed class HumanoidProfileTests : GameTest
|
||||
{
|
||||
private static readonly EntProtoId BaseSpecies = "MobHuman";
|
||||
private static readonly ProtoId<SpeciesPrototype> Vox = "Vox";
|
||||
private static readonly ProtoId<SpeciesPrototype> SlimePerson = "SlimePerson";
|
||||
public static readonly ProtoId<EmoteSoundsPrototype> SlimeVoice = "FemaleSlime";
|
||||
|
||||
private static string[] _species = GameDataScrounger.PrototypesOfKind<SpeciesPrototype>();
|
||||
|
||||
[SidedDependency(Side.Server)] private BodySystem _bodySystem = default!;
|
||||
|
|
@ -45,16 +48,20 @@ public sealed class HumanoidProfileTests : GameTest
|
|||
.WithSex(Sex.Female)
|
||||
.WithAge(67)
|
||||
.WithGender(Gender.Neuter)
|
||||
.WithSpecies(Vox));
|
||||
.WithSpecies(SlimePerson)
|
||||
.WithVoice(SlimeVoice));
|
||||
|
||||
var voiceComponent = SEntMan.GetComponent<VocalComponent>(body);
|
||||
|
||||
Assert.That(humanoidComponent.Age, Is.EqualTo(67));
|
||||
Assert.That(humanoidComponent.Sex, Is.EqualTo(Sex.Female));
|
||||
Assert.That(humanoidComponent.Gender, Is.EqualTo(Gender.Neuter));
|
||||
Assert.That(humanoidComponent.Species, Is.EqualTo(Vox));
|
||||
Assert.That(humanoidComponent.Species, Is.EqualTo(SlimePerson));
|
||||
Assert.That(humanoidComponent.Voice, Is.EqualTo(SlimeVoice));
|
||||
|
||||
Assert.That(voiceComponent.Sounds, Is.Not.Null, message: "the MobHuman spawned by this test needs to have sex-specific sound set");
|
||||
Assert.That(voiceComponent.Sounds![Sex.Female], Is.EqualTo(voiceComponent.EmoteSounds));
|
||||
var speciesProto = SProtoMan.Index(humanoidComponent.Species);
|
||||
|
||||
Assert.That(speciesProto.DefaultSoundsBySex[(int)Sex.Female], Is.EqualTo(voiceComponent.EmoteSounds));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -172,4 +179,32 @@ public sealed class HumanoidProfileTests : GameTest
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestOf(typeof(VocalComponent))]
|
||||
[TestCaseSource(nameof(_species))]
|
||||
[Description("Tests that if a species has corresponding UI entries for their VocalComponent, as well as sex mappings for their voice entry in speciesPrototype")]
|
||||
public async Task EnsureValidVoices(string species)
|
||||
{
|
||||
await Server.WaitIdleAsync();
|
||||
|
||||
await Server.WaitAssertion(() =>
|
||||
{
|
||||
var proto = SProtoMan.Index<SpeciesPrototype>(species);
|
||||
|
||||
// Species like skeletons don't need UI entries
|
||||
if (!proto.RoundStart)
|
||||
return;
|
||||
|
||||
var voiceProtos = proto.Voices;
|
||||
var sexedProtos = proto.DefaultSoundsBySex.ToHashSet();
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(sexedProtos.IsSubsetOf(voiceProtos), "Species with modified `DefaultSoundsBySex` should have an entry added to the `voice` field in the `speciesPrototype`");
|
||||
Assert.That(voiceProtos.Union(sexedProtos).Any(), "Species should have sex mappings for at least one voice set in speciesPrototype");
|
||||
Assert.That(proto.DefaultSoundsBySex, Has.Length.EqualTo(3), "Species should declare a defaultSoundsBySex for every sex");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2239
Content.Server.Database/Migrations/Postgres/20260701024227_VoiceSelector.Designer.cs
generated
Normal file
2239
Content.Server.Database/Migrations/Postgres/20260701024227_VoiceSelector.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,28 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class VoiceSelector : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "voice",
|
||||
table: "profile",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "voice",
|
||||
table: "profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.0")
|
||||
.HasAnnotation("ProductVersion", "10.0.6")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
|
@ -1191,6 +1191,10 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||
.HasColumnType("text")
|
||||
.HasColumnName("species");
|
||||
|
||||
b.Property<string>("Voice")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("voice");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_profile");
|
||||
|
||||
|
|
|
|||
2156
Content.Server.Database/Migrations/Sqlite/20260701024222_VoiceSelector.Designer.cs
generated
Normal file
2156
Content.Server.Database/Migrations/Sqlite/20260701024222_VoiceSelector.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,28 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class VoiceSelector : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "voice",
|
||||
table: "profile",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "voice",
|
||||
table: "profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.0");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.6");
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
|
|
@ -1126,6 +1126,10 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||
.HasColumnType("TEXT")
|
||||
.HasColumnName("species");
|
||||
|
||||
b.Property<string>("Voice")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("voice");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_profile");
|
||||
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ namespace Content.Server.Database
|
|||
public string FlavorText { get; set; } = null!;
|
||||
public int Age { get; set; }
|
||||
public string Sex { get; set; } = null!;
|
||||
public string? Voice { get; set; } = null!; // If null, the voice gets defaulted to the sex associated value
|
||||
public string Gender { get; set; } = null!;
|
||||
public string Species { get; set; } = null!;
|
||||
[Column(TypeName = "jsonb")] public JsonDocument? OrganMarkings { get; set; } = null!;
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ namespace Content.Server.Database
|
|||
profile.Species = humanoid.Species;
|
||||
profile.Age = humanoid.Age;
|
||||
profile.Sex = humanoid.Sex.ToString();
|
||||
profile.Voice = humanoid.Voice.ToString();
|
||||
profile.Gender = humanoid.Gender.ToString();
|
||||
profile.EyeColor = appearance.EyeColor.ToHex();
|
||||
profile.SkinColor = appearance.SkinColor.ToHex();
|
||||
|
|
|
|||
|
|
@ -112,8 +112,15 @@ namespace Content.Server.Preferences.Managers
|
|||
new Dictionary<ProtoId<OrganCategoryPrototype>, Dictionary<HumanoidVisualLayers, List<Marking>>>();
|
||||
|
||||
var species = profile.Species;
|
||||
if (!_prototypeManager.HasIndex<SpeciesPrototype>(species))
|
||||
if (!_prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
|
||||
{
|
||||
species = HumanoidCharacterProfile.DefaultSpecies;
|
||||
speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(species);
|
||||
}
|
||||
|
||||
var voice = profile.Voice ?? speciesPrototype.DefaultSoundsBySex[(int)sex];
|
||||
if (!_prototypeManager.HasIndex(voice))
|
||||
voice = speciesPrototype.DefaultSoundsBySex[(int)sex];
|
||||
|
||||
if (profile.OrganMarkings?.RootElement is { } element)
|
||||
{
|
||||
|
|
@ -175,6 +182,7 @@ namespace Content.Server.Preferences.Managers
|
|||
species,
|
||||
profile.Age,
|
||||
sex,
|
||||
voice,
|
||||
gender,
|
||||
new HumanoidCharacterAppearance
|
||||
(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Content.Shared.Speech;
|
|||
using Content.Shared.Speech.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Speech.EntitySystems;
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ public sealed partial class VocalSystem : EntitySystem
|
|||
|
||||
SubscribeLocalEvent<VocalComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<VocalComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<VocalComponent, SexChangedEvent>(OnSexChanged);
|
||||
SubscribeLocalEvent<VocalComponent, VoiceChangedEvent>(OnVoiceChanged);
|
||||
SubscribeLocalEvent<VocalComponent, EmoteEvent>(OnEmote);
|
||||
SubscribeLocalEvent<VocalComponent, EmoteActionEvent>(OnEmoteAction);
|
||||
}
|
||||
|
|
@ -38,7 +39,6 @@ public sealed partial class VocalSystem : EntitySystem
|
|||
return;
|
||||
|
||||
var targetComp = EnsureComp<VocalComponent>(target);
|
||||
targetComp.Sounds = source.Comp.Sounds;
|
||||
targetComp.ScreamId = source.Comp.ScreamId;
|
||||
targetComp.Wilhelm = source.Comp.Wilhelm;
|
||||
targetComp.WilhelmProbability = source.Comp.WilhelmProbability;
|
||||
|
|
@ -51,7 +51,6 @@ public sealed partial class VocalSystem : EntitySystem
|
|||
{
|
||||
// try to add scream action when vocal comp added
|
||||
_actions.AddAction(uid, ref component.EmoteActionEntity, component.EmoteAction);
|
||||
LoadSounds(uid, component);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, VocalComponent component, ComponentShutdown args)
|
||||
|
|
@ -63,9 +62,9 @@ public sealed partial class VocalSystem : EntitySystem
|
|||
}
|
||||
}
|
||||
|
||||
private void OnSexChanged(EntityUid uid, VocalComponent component, SexChangedEvent args)
|
||||
private void OnVoiceChanged(EntityUid uid, VocalComponent component, VoiceChangedEvent args)
|
||||
{
|
||||
LoadSounds(uid, component, args.NewSex);
|
||||
LoadSounds(uid, component, args.NewVoice);
|
||||
}
|
||||
|
||||
private void OnEmote(EntityUid uid, VocalComponent component, ref EmoteEvent args)
|
||||
|
|
@ -110,15 +109,15 @@ public sealed partial class VocalSystem : EntitySystem
|
|||
return _chat.TryPlayEmoteSound(uid, ProtoMan.Index(sounds), component.ScreamId);
|
||||
}
|
||||
|
||||
private void LoadSounds(EntityUid uid, VocalComponent component, Sex? sex = null)
|
||||
/// <summary>
|
||||
/// This only works on Humanoids. Mobs should have emoteSounds on <see cref="VocalComponent"/> set directly instead.
|
||||
/// </summary>
|
||||
private void LoadSounds(EntityUid uid, VocalComponent component, ProtoId<EmoteSoundsPrototype>? protoId = null)
|
||||
{
|
||||
if (component.Sounds == null)
|
||||
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
||||
return;
|
||||
|
||||
sex ??= CompOrNull<HumanoidProfileComponent>(uid)?.Sex ?? Sex.Unsexed;
|
||||
|
||||
if (!component.Sounds.TryGetValue(sex.Value, out var protoId))
|
||||
return;
|
||||
protoId ??= humanoid.Voice;
|
||||
|
||||
if (!ProtoMan.HasIndex(protoId))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ public sealed partial class EmoteSoundsPrototype : IPrototype, IInheritingProtot
|
|||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The name used for the Voice selector in the character editor UI.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId VoiceSelectorName { get; private set; } = "humanoid-profile-editor-voice-none";
|
||||
|
||||
/// <inheritdoc/>
|
||||
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<EmoteSoundsPrototype>))]
|
||||
public string[]? Parents { get; private set; }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Speech.Components;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
|
@ -16,6 +18,14 @@ public sealed partial class HumanoidProfileComponent : Component
|
|||
[DataField, AutoNetworkedField]
|
||||
public Gender Gender;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the EmoteSoundsPrototype that the humanoid will use to speak with
|
||||
/// To change in-game, you still have to use the <see cref="VoiceChangedEvent"/>
|
||||
/// or edit the <see cref="VocalComponent"/>
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<EmoteSoundsPrototype> Voice = HumanoidCharacterProfile.DefaultVoice;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Sex Sex;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Numerics;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences;
|
||||
|
|
@ -81,7 +82,16 @@ public sealed partial class HumanoidCharacterProfileV1
|
|||
|
||||
public HumanoidCharacterProfile ToV2()
|
||||
{
|
||||
return new(Name, FlavorText, Species, Age, Sex, Gender, Appearance.ToV2(Species), SpawnPriority, JobPriorities, PreferenceUnavailable, AntagPreferences, TraitPreferences, Loadouts);
|
||||
return new(Name, FlavorText, Species, Age, Sex, GetDefaultVoice(Species, Sex), Gender, Appearance.ToV2(Species), SpawnPriority, JobPriorities, PreferenceUnavailable, AntagPreferences, TraitPreferences, Loadouts);
|
||||
}
|
||||
|
||||
// In V2 voices are stored as a separate database entry, this picks the default for the species and sex, which would give the same voice as pre-nubody.
|
||||
private ProtoId<EmoteSoundsPrototype> GetDefaultVoice(ProtoId<SpeciesPrototype> species, Sex sex)
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<PrototypeManager>();
|
||||
|
||||
var speciesPrototye = prototypeManager.Index(species);
|
||||
return speciesPrototye.DefaultSoundsBySex[(int)sex];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,12 @@ public sealed partial class HumanoidProfileSystem : EntitySystem
|
|||
ent.Comp.Gender = profile.Gender;
|
||||
ent.Comp.Age = profile.Age;
|
||||
ent.Comp.Species = profile.Species;
|
||||
ent.Comp.Voice = profile.Voice;
|
||||
ent.Comp.Sex = profile.Sex;
|
||||
Dirty(ent);
|
||||
|
||||
var sexChanged = new SexChangedEvent(ent.Comp.Sex, profile.Sex);
|
||||
RaiseLocalEvent(ent, ref sexChanged);
|
||||
var voiceChanged = new VoiceChangedEvent(ent.Comp.Voice, profile.Voice);
|
||||
RaiseLocalEvent(ent, ref voiceChanged);
|
||||
|
||||
if (TryComp<GrammarComponent>(ent, out var grammar))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared.Body;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
|
@ -81,6 +82,18 @@ public sealed partial class SpeciesPrototype : IPrototype
|
|||
[DataField]
|
||||
public List<Sex> Sexes { get; private set; } = new() { Sex.Male, Sex.Female };
|
||||
|
||||
/// <summary>
|
||||
/// Emote sounds prototype conversion id for every sex. This is ALWAYS in the order: Male; Female; Unsexed.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<EmoteSoundsPrototype>[] DefaultSoundsBySex = ["MaleHuman", "FemaleHuman", "MaleHuman"];
|
||||
|
||||
/// <summary>
|
||||
/// List of user selectable voices in the menu. This should at least have the same sound banks as the defaults.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<ProtoId<EmoteSoundsPrototype>> Voices = ["MaleHuman", "FemaleHuman"];
|
||||
|
||||
/// <summary>
|
||||
/// Characters younger than this are too young to be hired by Nanotrasen.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared.Humanoid
|
||||
namespace Content.Shared.Humanoid
|
||||
{
|
||||
// You need to update profile, profile editor, maybe voices and names if you want to expand this further.
|
||||
public enum Sex : byte
|
||||
|
|
@ -12,11 +7,4 @@ namespace Content.Shared.Humanoid
|
|||
Female,
|
||||
Unsexed,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when entity has changed their sex.
|
||||
/// This doesn't handle gender changes.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct SexChangedEvent(Sex OldSex, Sex NewSex);
|
||||
}
|
||||
|
|
|
|||
11
Content.Shared/Humanoid/Voice.cs
Normal file
11
Content.Shared/Humanoid/Voice.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using Content.Shared.Chat.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Humanoid;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when entity has changed their voice.
|
||||
/// This doesn't handle gender changes.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct VoiceChangedEvent(ProtoId<EmoteSoundsPrototype>? OldVoice, ProtoId<EmoteSoundsPrototype>? NewVoice);
|
||||
|
|
@ -2,11 +2,14 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.EntityEffects.Effects;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Speech.Components;
|
||||
using Content.Shared.Traits;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
|
|
@ -31,6 +34,7 @@ namespace Content.Shared.Preferences
|
|||
public sealed partial class HumanoidCharacterProfile
|
||||
{
|
||||
public static readonly ProtoId<SpeciesPrototype> DefaultSpecies = "Human";
|
||||
public static readonly ProtoId<EmoteSoundsPrototype> DefaultVoice = "MaleHuman";
|
||||
private static readonly Regex RestrictedNameRegex = new(@"[^A-Za-z0-9 '\-]");
|
||||
private static readonly Regex ICNameCaseRegex = new(@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)");
|
||||
|
||||
|
|
@ -86,6 +90,9 @@ namespace Content.Shared.Preferences
|
|||
[DataField]
|
||||
public Sex Sex { get; private set; } = Sex.Male;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<EmoteSoundsPrototype> Voice { get; set; } = DefaultVoice;
|
||||
|
||||
[DataField]
|
||||
public Gender Gender { get; private set; } = Gender.Male;
|
||||
|
||||
|
|
@ -129,6 +136,7 @@ namespace Content.Shared.Preferences
|
|||
string species,
|
||||
int age,
|
||||
Sex sex,
|
||||
ProtoId<EmoteSoundsPrototype> voice,
|
||||
Gender gender,
|
||||
HumanoidCharacterAppearance appearance,
|
||||
SpawnPriorityPreference spawnPriority,
|
||||
|
|
@ -143,6 +151,7 @@ namespace Content.Shared.Preferences
|
|||
Species = species;
|
||||
Age = age;
|
||||
Sex = sex;
|
||||
Voice = voice;
|
||||
Gender = gender;
|
||||
Appearance = appearance;
|
||||
SpawnPriority = spawnPriority;
|
||||
|
|
@ -174,6 +183,7 @@ namespace Content.Shared.Preferences
|
|||
other.Species,
|
||||
other.Age,
|
||||
other.Sex,
|
||||
other.Voice,
|
||||
other.Gender,
|
||||
other.Appearance.Clone(),
|
||||
other.SpawnPriority,
|
||||
|
|
@ -237,10 +247,12 @@ namespace Content.Shared.Preferences
|
|||
|
||||
var sex = Sex.Unsexed;
|
||||
var age = 18;
|
||||
var voice = DefaultVoice; // Banishing someone to no voice would be unfortunate
|
||||
if (prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
|
||||
{
|
||||
sex = random.Pick(speciesPrototype.Sexes);
|
||||
age = random.Next(speciesPrototype.MinAge, speciesPrototype.OldAge); // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged
|
||||
voice = speciesPrototype.DefaultSoundsBySex[(int)sex];
|
||||
}
|
||||
|
||||
var gender = Gender.Epicene;
|
||||
|
|
@ -261,6 +273,7 @@ namespace Content.Shared.Preferences
|
|||
{
|
||||
Name = name,
|
||||
Sex = sex,
|
||||
Voice = voice,
|
||||
Age = age,
|
||||
Gender = gender,
|
||||
Species = species,
|
||||
|
|
@ -288,6 +301,11 @@ namespace Content.Shared.Preferences
|
|||
return new(this) { Sex = sex };
|
||||
}
|
||||
|
||||
public HumanoidCharacterProfile WithVoice(ProtoId<EmoteSoundsPrototype> voice)
|
||||
{
|
||||
return new(this) { Voice = voice };
|
||||
}
|
||||
|
||||
public HumanoidCharacterProfile WithGender(Gender gender)
|
||||
{
|
||||
return new(this) { Gender = gender };
|
||||
|
|
@ -496,6 +514,10 @@ namespace Content.Shared.Preferences
|
|||
_ => Sex.Male // Invalid enum values.
|
||||
};
|
||||
|
||||
var voice = Voice;
|
||||
if (!speciesPrototype.Voices.Contains(voice))
|
||||
voice = speciesPrototype.DefaultSoundsBySex[(int)sex];
|
||||
|
||||
// ensure the species can be that sex and their age fits the founds
|
||||
if (!speciesPrototype.Sexes.Contains(sex))
|
||||
sex = speciesPrototype.Sexes[0];
|
||||
|
|
@ -605,6 +627,7 @@ namespace Content.Shared.Preferences
|
|||
FlavorText = flavortext;
|
||||
Age = age;
|
||||
Sex = sex;
|
||||
Voice = voice;
|
||||
Gender = gender;
|
||||
Appearance = appearance;
|
||||
SpawnPriority = spawnPriority;
|
||||
|
|
@ -725,6 +748,7 @@ namespace Content.Shared.Preferences
|
|||
hashCode.Add(Species);
|
||||
hashCode.Add(Age);
|
||||
hashCode.Add((int)Sex);
|
||||
hashCode.Add(Voice);
|
||||
hashCode.Add((int)Gender);
|
||||
hashCode.Add(Appearance);
|
||||
hashCode.Add((int)SpawnPriority);
|
||||
|
|
|
|||
|
|
@ -13,14 +13,6 @@ namespace Content.Shared.Speech.Components;
|
|||
[AutoGenerateComponentState]
|
||||
public sealed partial class VocalComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Emote sounds prototype id for each sex (not gender).
|
||||
/// Entities without <see cref="HumanoidComponent"/> considered to be <see cref="Sex.Unsexed"/>.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public Dictionary<Sex, ProtoId<EmoteSoundsPrototype>>? Sounds;
|
||||
|
||||
//TODO: Wilhelm scream logic needs to be more generic
|
||||
/// <summary>
|
||||
/// Emote ID for screaming (for whilhelm scream)
|
||||
|
|
@ -55,10 +47,11 @@ public sealed partial class VocalComponent : Component
|
|||
public EntityUid? EmoteActionEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Currently loaded emote sounds prototype, based on entity sex.
|
||||
/// Currently loaded emote sounds prototype, based on entity sex on humanoids.
|
||||
/// Null if no valid prototype for entity sex was found.
|
||||
/// Generally everything should have this set. This provides the sounds for Urists as well.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public ProtoId<EmoteSoundsPrototype>? EmoteSounds = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ humanoid-profile-editor-sex-label = Sex:
|
|||
humanoid-profile-editor-sex-male-text = Male
|
||||
humanoid-profile-editor-sex-female-text = Female
|
||||
humanoid-profile-editor-sex-unsexed-text = None
|
||||
humanoid-profile-editor-voice-label = Voice:
|
||||
humanoid-profile-editor-age-label = Age:
|
||||
humanoid-profile-editor-skin-color-label = Skin color:
|
||||
humanoid-profile-editor-species-label = Species:
|
||||
|
|
@ -62,3 +63,9 @@ humanoid-profile-editor-trait-count-hint = Points available: [{$current}/{$max}]
|
|||
trait-category-disabilities = Disabilities
|
||||
trait-category-speech = Speech traits
|
||||
trait-category-quirks = Quirks
|
||||
|
||||
# Voices
|
||||
humanoid-profile-editor-voice-masculine = Masculine
|
||||
humanoid-profile-editor-voice-feminine = Feminine
|
||||
humanoid-profile-editor-voice-neutral = Neutral
|
||||
humanoid-profile-editor-voice-none = Unnamed Voice
|
||||
|
|
|
|||
|
|
@ -132,10 +132,7 @@
|
|||
speechSounds: Arachnid
|
||||
allowedEmotes: ['Click', 'Chitter']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexArachnid
|
||||
Female: UnisexArachnid
|
||||
Unsexed: UnisexArachnid
|
||||
emoteSounds: UnisexArachnid
|
||||
- type: TypingIndicator
|
||||
proto: spider
|
||||
- type: CreamPied
|
||||
|
|
|
|||
|
|
@ -153,10 +153,7 @@
|
|||
speechVerb: Plant
|
||||
allowedEmotes: ['Chirp']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexDiona
|
||||
Female: UnisexDiona
|
||||
Unsexed: UnisexDiona
|
||||
emoteSounds: UnisexDiona
|
||||
- type: TypingIndicator
|
||||
proto: diona
|
||||
- type: BodyEmotes
|
||||
|
|
|
|||
|
|
@ -59,10 +59,7 @@
|
|||
layer:
|
||||
- MobLayer
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexDwarf
|
||||
Female: FemaleDwarf
|
||||
Unsexed: UnisexDwarf
|
||||
emoteSounds: UnisexDwarf
|
||||
- type: ReplacementAccent
|
||||
accent: scottish
|
||||
- type: Speech
|
||||
|
|
|
|||
|
|
@ -167,10 +167,7 @@
|
|||
sprite: Mobs/Effects/burn_damage.rsi
|
||||
- type: MothAccent
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexMoth
|
||||
Female: UnisexMoth
|
||||
Unsexed: UnisexMoth
|
||||
emoteSounds: UnisexMoth
|
||||
- type: BodyEmotes
|
||||
soundsId: MothBodyEmotes
|
||||
- type: MovementSpeedModifier
|
||||
|
|
|
|||
|
|
@ -136,10 +136,7 @@
|
|||
sprite: Effects/creampie.rsi
|
||||
state: creampie_lizard
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleReptilian
|
||||
Female: FemaleReptilian
|
||||
Unsexed: MaleReptilian
|
||||
emoteSounds: MaleReptilian
|
||||
- type: BodyEmotes
|
||||
soundsId: ReptilianBodyEmotes
|
||||
- type: Damageable
|
||||
|
|
|
|||
|
|
@ -106,10 +106,7 @@
|
|||
speechVerb: Skeleton
|
||||
- type: ZombieImmune
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Skeleton
|
||||
Female: Skeleton
|
||||
Unsexed: Skeleton
|
||||
emoteSounds: Skeleton
|
||||
- type: SkeletonAccent
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
|
|
|
|||
|
|
@ -108,10 +108,7 @@
|
|||
- type: TypingIndicator
|
||||
proto: slime
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleSlime
|
||||
Female: FemaleSlime
|
||||
Unsexed: MaleSlime
|
||||
emoteSounds: MaleSlime
|
||||
- type: Damageable
|
||||
damageModifierSet: Slime
|
||||
- type: PassiveDamage # Around 8 damage a minute healed
|
||||
|
|
|
|||
|
|
@ -176,10 +176,7 @@
|
|||
sprite: Effects/creampie.rsi
|
||||
state: creampie_vox
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexVox
|
||||
Female: UnisexVox
|
||||
Unsexed: UnisexVox
|
||||
emoteSounds: UnisexVox
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatChicken
|
||||
|
|
|
|||
|
|
@ -162,10 +162,7 @@
|
|||
- type: TypingIndicator
|
||||
proto: vulpkanin
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleVulpkanin
|
||||
Female: FemaleVulpkanin
|
||||
Unsexed: MaleVulpkanin
|
||||
emoteSounds: MaleVulpkanin
|
||||
- type: Damageable
|
||||
damageModifierSet: Vulpkanin
|
||||
- type: MeleeWeapon
|
||||
|
|
|
|||
|
|
@ -136,10 +136,7 @@
|
|||
speechSounds: Alto
|
||||
- type: DamageForceSay
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleHuman
|
||||
Female: FemaleHuman
|
||||
Unsexed: MaleHuman
|
||||
emoteSounds: MaleHuman
|
||||
- type: Emoting
|
||||
- type: BodyEmotes
|
||||
soundsId: GeneralBodyEmotes
|
||||
|
|
|
|||
|
|
@ -145,8 +145,7 @@
|
|||
speechVerb: Robotic
|
||||
speechSounds: Borg
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSilicon
|
||||
emoteSounds: UnisexSilicon
|
||||
wilhelmProbability: 0
|
||||
- type: DamagedSiliconAccent
|
||||
- type: UnblockableSpeech
|
||||
|
|
@ -369,8 +368,7 @@
|
|||
allowedEmotes:
|
||||
- Laugh
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSiliconSyndicate
|
||||
emoteSounds: UnisexSiliconSyndicate
|
||||
- type: PointLight
|
||||
color: "#dd200b"
|
||||
- type: BypassLock
|
||||
|
|
@ -430,8 +428,7 @@
|
|||
allowedEmotes:
|
||||
- Laugh
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSiliconSyndicate
|
||||
emoteSounds: UnisexSiliconSyndicate
|
||||
- type: PointLight
|
||||
color: "#dd200b"
|
||||
- type: BypassLock
|
||||
|
|
@ -485,8 +482,7 @@
|
|||
allowedEmotes:
|
||||
- Laugh
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSiliconXenoborg
|
||||
emoteSounds: UnisexSiliconXenoborg
|
||||
wilhelmProbability: 0
|
||||
- type: DamagedSiliconAccent
|
||||
- type: UnblockableSpeech
|
||||
|
|
|
|||
|
|
@ -580,10 +580,7 @@
|
|||
- type: ZombieAccentOverride
|
||||
accent: zombieMoth
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexMoth
|
||||
Female: UnisexMoth
|
||||
Unsexed: UnisexMoth
|
||||
emoteSounds: UnisexMoth
|
||||
wilhelmProbability: 0.001
|
||||
- type: BodyEmotes
|
||||
soundsId: MothBodyEmotes
|
||||
|
|
@ -1088,10 +1085,7 @@
|
|||
speechSounds: Goat
|
||||
speechVerb: Goat
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Female: Goat
|
||||
Male: Goat
|
||||
Unsexed: Goat
|
||||
emoteSounds: Goat
|
||||
- type: BleatingAccent
|
||||
- type: InteractionPopup
|
||||
successChance: 0.2
|
||||
|
|
@ -1225,10 +1219,7 @@
|
|||
speechSounds: Sheep
|
||||
speechVerb: Sheep
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Female: Sheep
|
||||
Male: Sheep
|
||||
Unsexed: Sheep
|
||||
emoteSounds: Sheep
|
||||
- type: BleatingAccent
|
||||
- type: InteractionPopup
|
||||
successChance: 0.8 #SHEEP so FRIEND!!! HUG! SQUISHY! SOFT!
|
||||
|
|
@ -1515,8 +1506,7 @@
|
|||
rules: ghost-role-information-nonantagonist-rules
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: Kangaroo
|
||||
emoteSounds: Kangaroo
|
||||
- type: Puller
|
||||
needsHands: false
|
||||
- type: StaminaDamageOnHit
|
||||
|
|
@ -1770,10 +1760,7 @@
|
|||
speechVerb: Reptilian
|
||||
allowedEmotes: ['Thump']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: MaleReptilian
|
||||
Female: FemaleReptilian
|
||||
Unsexed: MaleReptilian
|
||||
emoteSounds: MaleReptilian
|
||||
- type: BodyEmotes
|
||||
soundsId: ReptilianBodyEmotes
|
||||
- type: TypingIndicator
|
||||
|
|
@ -2056,10 +2043,7 @@
|
|||
types:
|
||||
Blunt: 0.1
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Mouse
|
||||
Female: Mouse
|
||||
Unsexed: Mouse
|
||||
emoteSounds: Mouse
|
||||
wilhelmProbability: 0.001
|
||||
# TODO: Remove CombatMode when Prototype Composition is added
|
||||
- type: CombatMode
|
||||
|
|
@ -2447,8 +2431,7 @@
|
|||
speechSounds: Parrot
|
||||
speechVerb: Parrot
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: Parrot
|
||||
emoteSounds: Parrot
|
||||
- type: ActiveListener
|
||||
- type: Vocalizer
|
||||
- type: RadioVocalizer
|
||||
|
|
@ -2737,10 +2720,7 @@
|
|||
speechSounds: Arachnid
|
||||
allowedEmotes: ['Click', 'Chitter']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexArachnid
|
||||
Female: UnisexArachnid
|
||||
Unsexed: UnisexArachnid
|
||||
emoteSounds: UnisexArachnid
|
||||
- type: TypingIndicator
|
||||
proto: spider
|
||||
- type: Tag
|
||||
|
|
@ -3916,10 +3896,7 @@
|
|||
speechSounds: Alto
|
||||
allowedEmotes: ['Chirp']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexDiona
|
||||
Female: UnisexDiona
|
||||
Unsexed: UnisexDiona
|
||||
emoteSounds: UnisexDiona
|
||||
- type: Tag
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
|
|
|
|||
|
|
@ -283,10 +283,7 @@
|
|||
- id: FoodMeatRat
|
||||
amount: 1
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Mouse
|
||||
Female: Mouse
|
||||
Unsexed: Mouse
|
||||
emoteSounds: Mouse
|
||||
wilhelmProbability: 0.001
|
||||
- type: Tag
|
||||
tags:
|
||||
|
|
|
|||
|
|
@ -48,10 +48,7 @@
|
|||
amount: 4
|
||||
# They wawa!
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Scurret
|
||||
Female: Scurret
|
||||
Unsexed: Scurret
|
||||
emoteSounds: Scurret
|
||||
wilhelmProbability: 0.01 # the scug, it screams like a man
|
||||
- type: Speech
|
||||
speechVerb: Wawa
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@
|
|||
- type: TypingIndicator
|
||||
proto: robot
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSilicon
|
||||
emoteSounds: UnisexSilicon
|
||||
- type: Emoting
|
||||
- type: ZombieImmune
|
||||
- type: ProtectedFromStepTriggers
|
||||
|
|
@ -245,8 +244,7 @@
|
|||
params:
|
||||
variation: 0.125
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: Cluwne
|
||||
emoteSounds: Cluwne
|
||||
- type: ExplodeOnTrigger
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
|
|
|
|||
|
|
@ -105,8 +105,7 @@
|
|||
- type: ReplacementAccent
|
||||
accent: genericAggressive
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: Bear
|
||||
emoteSounds: Bear
|
||||
- type: InteractionPopup
|
||||
successChance: 0.25
|
||||
interactSuccessString: petting-success-bear
|
||||
|
|
@ -163,8 +162,7 @@
|
|||
speciesId: kangaroo
|
||||
templateId: spacekangaroo
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: Kangaroo
|
||||
emoteSounds: Kangaroo
|
||||
- type: ReplacementAccent
|
||||
accent: kangaroo
|
||||
- type: ToolRefinable
|
||||
|
|
@ -266,10 +264,7 @@
|
|||
speechSounds: Arachnid
|
||||
allowedEmotes: ['Click', 'Chitter']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexArachnid
|
||||
Female: UnisexArachnid
|
||||
Unsexed: UnisexArachnid
|
||||
emoteSounds: UnisexArachnid
|
||||
- type: TypingIndicator
|
||||
proto: spider
|
||||
|
||||
|
|
@ -487,10 +482,7 @@
|
|||
speechSounds: SheepSpace
|
||||
speechVerb: Sheep
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Female: SheepSpace
|
||||
Male: SheepSpace
|
||||
Unsexed: SheepSpace
|
||||
emoteSounds: SheepSpace
|
||||
|
||||
- type: entity
|
||||
parent: [SimpleSpaceMobBase, BaseMobAnimal, SolutionVermin, MobNightVision]
|
||||
|
|
|
|||
|
|
@ -90,7 +90,4 @@
|
|||
- type: MindExaminable
|
||||
- type: Familiar
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Cerberus
|
||||
Female: Cerberus
|
||||
Unsexed: Cerberus
|
||||
emoteSounds: Cerberus
|
||||
|
|
|
|||
|
|
@ -136,8 +136,7 @@
|
|||
allowedEmotes:
|
||||
- Laugh
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSiliconXenoborg
|
||||
emoteSounds: UnisexSiliconXenoborg
|
||||
wilhelmProbability: 0
|
||||
- type: IntrinsicRadioReceiver
|
||||
- type: IntrinsicRadioTransmitter
|
||||
|
|
|
|||
|
|
@ -97,8 +97,7 @@
|
|||
- SecretStash
|
||||
- WrappedParcel
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSilicon
|
||||
emoteSounds: UnisexSilicon
|
||||
- type: Tag
|
||||
tags:
|
||||
- SiliconEmotes
|
||||
|
|
@ -139,8 +138,7 @@
|
|||
- type: StaticPrice
|
||||
price: 500
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Unsexed: UnisexSiliconSyndicate
|
||||
emoteSounds: UnisexSiliconSyndicate
|
||||
|
||||
- type: entity
|
||||
parent: PersonalAI
|
||||
|
|
|
|||
|
|
@ -11,3 +11,9 @@
|
|||
lastNames: NamesArachnidLast
|
||||
sexes:
|
||||
- Unsexed
|
||||
defaultSoundsBySex:
|
||||
- UnisexArachnid
|
||||
- UnisexArachnid
|
||||
- UnisexArachnid
|
||||
voices:
|
||||
- UnisexArachnid
|
||||
|
|
|
|||
|
|
@ -12,3 +12,9 @@
|
|||
naming: TheFirstofLast
|
||||
sexes:
|
||||
- Unsexed
|
||||
defaultSoundsBySex:
|
||||
- UnisexDiona
|
||||
- UnisexDiona
|
||||
- UnisexDiona
|
||||
voices:
|
||||
- UnisexDiona
|
||||
|
|
|
|||
|
|
@ -5,3 +5,10 @@
|
|||
prototype: MobDwarf
|
||||
dollPrototype: AppearanceDwarf
|
||||
skinColoration: HumanToned
|
||||
defaultSoundsBySex:
|
||||
- UnisexDwarf
|
||||
- FemaleDwarf
|
||||
- UnisexDwarf
|
||||
voices:
|
||||
- UnisexDwarf
|
||||
- FemaleDwarf
|
||||
|
|
|
|||
|
|
@ -9,3 +9,9 @@
|
|||
maleFirstNames: NamesMothFirstMale
|
||||
femaleFirstNames: NamesMothFirstFemale
|
||||
lastNames: NamesMothLast
|
||||
defaultSoundsBySex:
|
||||
- UnisexMoth
|
||||
- UnisexMoth
|
||||
- UnisexMoth
|
||||
voices:
|
||||
- UnisexMoth
|
||||
|
|
|
|||
|
|
@ -9,3 +9,10 @@
|
|||
maleFirstNames: NamesReptilianMale
|
||||
femaleFirstNames: NamesReptilianFemale
|
||||
naming: FirstDashFirst
|
||||
defaultSoundsBySex:
|
||||
- MaleReptilian
|
||||
- FemaleReptilian
|
||||
- MaleReptilian
|
||||
voices:
|
||||
- MaleReptilian
|
||||
- FemaleReptilian
|
||||
|
|
|
|||
|
|
@ -6,3 +6,10 @@
|
|||
defaultSkinTone: "#b8b8b8"
|
||||
dollPrototype: AppearanceSlimePerson
|
||||
skinColoration: Hues
|
||||
defaultSoundsBySex:
|
||||
- MaleSlime
|
||||
- FemaleSlime
|
||||
- MaleSlime
|
||||
voices:
|
||||
- MaleSlime
|
||||
- FemaleSlime
|
||||
|
|
|
|||
|
|
@ -11,3 +11,9 @@
|
|||
naming: First
|
||||
sexes:
|
||||
- Unsexed
|
||||
defaultSoundsBySex:
|
||||
- UnisexVox
|
||||
- UnisexVox
|
||||
- UnisexVox
|
||||
voices:
|
||||
- UnisexVox
|
||||
|
|
|
|||
|
|
@ -9,3 +9,10 @@
|
|||
maleFirstNames: names_vulpkanin_male
|
||||
femaleFirstNames: names_vulpkanin_female
|
||||
lastNames: names_vulpkanin_last
|
||||
defaultSoundsBySex:
|
||||
- MaleVulpkanin
|
||||
- FemaleVulpkanin
|
||||
- MaleVulpkanin
|
||||
voices:
|
||||
- MaleVulpkanin
|
||||
- FemaleVulpkanin
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# species
|
||||
- type: emoteSounds
|
||||
id: MaleHuman
|
||||
voiceSelectorName: humanoid-profile-editor-voice-masculine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -43,6 +44,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: FemaleHuman
|
||||
voiceSelectorName: humanoid-profile-editor-voice-feminine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -85,6 +87,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: MaleReptilian
|
||||
voiceSelectorName: humanoid-profile-editor-voice-masculine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -109,6 +112,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: FemaleReptilian
|
||||
voiceSelectorName: humanoid-profile-editor-voice-feminine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -133,6 +137,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: MaleSlime
|
||||
voiceSelectorName: humanoid-profile-editor-voice-masculine
|
||||
sounds:
|
||||
Squish:
|
||||
collection: Squishes
|
||||
|
|
@ -177,6 +182,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: FemaleSlime
|
||||
voiceSelectorName: humanoid-profile-editor-voice-feminine
|
||||
sounds:
|
||||
Squish:
|
||||
collection: Squishes
|
||||
|
|
@ -221,6 +227,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: UnisexVox
|
||||
voiceSelectorName: humanoid-profile-editor-voice-neutral
|
||||
sounds:
|
||||
Scream:
|
||||
path: /Audio/Voice/Vox/shriek1.ogg
|
||||
|
|
@ -254,6 +261,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: UnisexDiona
|
||||
voiceSelectorName: humanoid-profile-editor-voice-neutral
|
||||
sounds:
|
||||
Scream:
|
||||
path: /Audio/Voice/Diona/diona_scream.ogg
|
||||
|
|
@ -278,6 +286,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: UnisexArachnid
|
||||
voiceSelectorName: humanoid-profile-editor-voice-neutral
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -302,6 +311,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: UnisexDwarf
|
||||
voiceSelectorName: humanoid-profile-editor-voice-masculine
|
||||
sounds:
|
||||
Scream:
|
||||
collection: MaleScreams
|
||||
|
|
@ -345,6 +355,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: FemaleDwarf
|
||||
voiceSelectorName: humanoid-profile-editor-voice-feminine
|
||||
sounds:
|
||||
Scream:
|
||||
collection: FemaleScreams
|
||||
|
|
@ -388,6 +399,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: UnisexMoth
|
||||
voiceSelectorName: humanoid-profile-editor-voice-neutral
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -479,6 +491,7 @@
|
|||
# Vulp Sounds
|
||||
- type: emoteSounds
|
||||
id: MaleVulpkanin
|
||||
voiceSelectorName: humanoid-profile-editor-voice-masculine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
@ -521,6 +534,7 @@
|
|||
|
||||
- type: emoteSounds
|
||||
id: FemaleVulpkanin
|
||||
voiceSelectorName: humanoid-profile-editor-voice-feminine
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue