From: Tayrtahn Date: Mon, 25 Mar 2024 01:26:41 +0000 (-0400) Subject: Make parrots talk like parrots (#26340) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=cd4eda44b88a75d7498efca42c464dd4c73c5684;p=space-station-14.git Make parrots talk like parrots (#26340) --- diff --git a/Content.Server/Speech/Components/ParrotAccentComponent.cs b/Content.Server/Speech/Components/ParrotAccentComponent.cs new file mode 100644 index 0000000000..5c4e01527c --- /dev/null +++ b/Content.Server/Speech/Components/ParrotAccentComponent.cs @@ -0,0 +1,47 @@ +namespace Content.Server.Speech.Components; + +/// +/// Makes this entity speak like a parrot in all chat messages it sends. +/// +[RegisterComponent] +public sealed partial class ParrotAccentComponent : Component +{ + /// + /// Chance that a message will have a squawk sound added before the first character. + /// If it fails, the message with have a squawk as a postfix instead. + /// If the longest word is repeated, no pre- or postfix will be added. + /// + [DataField] + public float SquawkPrefixChance = 0.5f; + + /// + /// Chance that the longest word in the message will be repeated as an + /// exclamation at the end of the final message. + /// + [DataField] + public float LongestWordRepeatChance = 0.5f; + + /// + /// The longest word must be at least this many characters long to be + /// repeated. This prevents repeating short words, which can sound weird. + /// ex: "How are you? AWWK! How!" - bad + /// ex: "Look out, it's the captain! RAWWK! Captain!" - good + /// + [DataField] + public float LongestWordMinLength = 5; + + /// + /// Strings to use as squawking noises. + /// + public readonly string[] Squawks = [ + "accent-parrot-squawk-1", + "accent-parrot-squawk-2", + "accent-parrot-squawk-3", + "accent-parrot-squawk-4", + "accent-parrot-squawk-5", + "accent-parrot-squawk-6", + "accent-parrot-squawk-7", + "accent-parrot-squawk-8" + ]; + +} diff --git a/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs b/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs new file mode 100644 index 0000000000..10437c235d --- /dev/null +++ b/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs @@ -0,0 +1,79 @@ +using System.Linq; +using System.Text.RegularExpressions; +using Content.Server.Speech.Components; +using Robust.Shared.Random; + +namespace Content.Server.Speech.EntitySystems; + +public sealed partial class ParrotAccentSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAccentGet); + } + + private void OnAccentGet(Entity entity, ref AccentGetEvent args) + { + args.Message = Accentuate(entity, args.Message); + } + + public string Accentuate(Entity entity, string message) + { + // Sometimes repeat the longest word at the end of the message, after a squawk! SQUAWK! Sometimes! + if (_random.Prob(entity.Comp.LongestWordRepeatChance)) + { + // Don't count non-alphanumeric characters as parts of words + var cleaned = Regex.Replace(message, "[^A-Za-z0-9 -]", string.Empty); + // Split on whitespace and favor words towards the end of the message + var words = cleaned.Split(null).Reverse(); + // Find longest word + var longest = words.MaxBy(word => word.Length); + if (longest?.Length >= entity.Comp.LongestWordMinLength) + { + message = EnsurePunctuation(message); + + // Capitalize the first letter of the repeated word + longest = string.Concat(longest[0].ToString().ToUpper(), longest.AsSpan(1)); + + message = string.Format("{0} {1} {2}!", message, GetRandomSquawk(entity), longest); + return message; // No more changes, or it's too much + } + } + + if (_random.Prob(entity.Comp.SquawkPrefixChance)) + { + // AWWK! Sometimes add a squawk at the begining of the message + message = string.Format("{0} {1}", GetRandomSquawk(entity), message); + } + else + { + // Otherwise add a squawk at the end of the message! RAWWK! + message = EnsurePunctuation(message); + message = string.Format("{0} {1}", message, GetRandomSquawk(entity)); + } + + return message; + } + + /// + /// Adds a "!" to the end of the string, if there isn't already a sentence-ending punctuation mark. + /// + private string EnsurePunctuation(string message) + { + if (!message.EndsWith('!') && !message.EndsWith('?') && !message.EndsWith('.')) + return message + '!'; + return message; + } + + /// + /// Returns a random, localized squawk sound. + /// + private string GetRandomSquawk(Entity entity) + { + return Loc.GetString(_random.Pick(entity.Comp.Squawks)); + } +} diff --git a/Resources/Locale/en-US/accent/parrot.ftl b/Resources/Locale/en-US/accent/parrot.ftl new file mode 100644 index 0000000000..4d4e0dc7e3 --- /dev/null +++ b/Resources/Locale/en-US/accent/parrot.ftl @@ -0,0 +1,8 @@ +accent-parrot-squawk-1 = SQUAWK! +accent-parrot-squawk-2 = SQUAAAWK! +accent-parrot-squawk-3 = AWWK! +accent-parrot-squawk-4 = AAWK! +accent-parrot-squawk-5 = RAWWK! +accent-parrot-squawk-6 = RAAAWK! +accent-parrot-squawk-7 = BRAAWK! +accent-parrot-squawk-8 = BRAWWK! diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index e5ef61701a..cf8c384dee 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -109,6 +109,10 @@ chat-speech-verb-large-mob-2 = growls chat-speech-verb-monkey-1 = chimpers chat-speech-verb-monkey-2 = screeches +chat-speech-verb-parrot-1 = squawks +chat-speech-verb-parrot-2 = tweets +chat-speech-verb-parrot-3 = chirps + chat-speech-verb-cluwne-1 = giggles chat-speech-verb-cluwne-2 = guffaws chat-speech-verb-cluwne-3 = laughs diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 170e4fc57a..de9a3db19e 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1865,6 +1865,13 @@ spawned: - id: FoodMeat amount: 1 + - type: Speech + speechSounds: Parrot + speechVerb: Parrot + - type: Vocal + sounds: + Unsexed: Parrot + - type: ParrotAccent - type: InteractionPopup successChance: 0.6 interactSuccessString: petting-success-bird diff --git a/Resources/Prototypes/Voice/speech_emote_sounds.yml b/Resources/Prototypes/Voice/speech_emote_sounds.yml index ee76fa33d2..01fabbadf3 100644 --- a/Resources/Prototypes/Voice/speech_emote_sounds.yml +++ b/Resources/Prototypes/Voice/speech_emote_sounds.yml @@ -380,3 +380,10 @@ sounds: Chirp: path: /Audio/Animals/nymph_chirp.ogg + +- type: emoteSounds + id: Parrot + sound: + path: /Audio/Animals/parrot_raught.ogg + params: + variation: 0.125 diff --git a/Resources/Prototypes/Voice/speech_sounds.yml b/Resources/Prototypes/Voice/speech_sounds.yml index eb47b5363b..2e7e7bf989 100644 --- a/Resources/Prototypes/Voice/speech_sounds.yml +++ b/Resources/Prototypes/Voice/speech_sounds.yml @@ -70,6 +70,15 @@ exclaimSound: path: /Audio/Animals/monkey_scream.ogg +- type: speechSounds + id: Parrot + saySound: + path: /Audio/Animals/parrot_raught.ogg + askSound: + path: /Audio/Animals/parrot_raught.ogg + exclaimSound: + path: /Audio/Animals/parrot_raught.ogg + - type: speechSounds id: Lizard saySound: diff --git a/Resources/Prototypes/Voice/speech_verbs.yml b/Resources/Prototypes/Voice/speech_verbs.yml index 1cdda32ece..26e9370c01 100644 --- a/Resources/Prototypes/Voice/speech_verbs.yml +++ b/Resources/Prototypes/Voice/speech_verbs.yml @@ -113,6 +113,13 @@ - chat-speech-verb-monkey-1 - chat-speech-verb-monkey-2 +- type: speechVerb + id: Parrot + speechVerbStrings: + - chat-speech-verb-parrot-1 + - chat-speech-verb-parrot-2 + - chat-speech-verb-parrot-3 + - type: speechVerb id: Cluwne speechVerbStrings: