2023-12-22 09:13:45 -05:00
using System.Collections.Frozen ;
2023-01-25 17:29:41 +01:00
using Content.Shared.Chat.Prototypes ;
using Robust.Shared.Prototypes ;
using Robust.Shared.Random ;
namespace Content.Server.Chat.Systems ;
// emotes using emote prototype
public partial class ChatSystem
{
2023-12-22 09:13:45 -05:00
private FrozenDictionary < string , EmotePrototype > _wordEmoteDict = FrozenDictionary < string , EmotePrototype > . Empty ;
2023-01-25 17:29:41 +01:00
2023-12-22 09:13:45 -05:00
protected override void OnPrototypeReload ( PrototypesReloadedEventArgs obj )
2023-01-25 17:29:41 +01:00
{
2023-12-22 09:13:45 -05:00
base . OnPrototypeReload ( obj ) ;
if ( obj . WasModified < EmotePrototype > ( ) )
CacheEmotes ( ) ;
2023-01-25 17:29:41 +01:00
}
private void CacheEmotes ( )
{
2023-12-22 09:13:45 -05:00
var dict = new Dictionary < string , EmotePrototype > ( ) ;
2023-01-25 17:29:41 +01:00
var emotes = _prototypeManager . EnumeratePrototypes < EmotePrototype > ( ) ;
foreach ( var emote in emotes )
{
2023-04-28 05:08:05 +06:00
if ( emote . ChatTriggers = = null )
continue ;
2023-01-25 17:29:41 +01:00
foreach ( var word in emote . ChatTriggers )
{
var lowerWord = word . ToLower ( ) ;
2023-12-22 09:13:45 -05:00
if ( dict . TryGetValue ( lowerWord , out var value ) )
2023-01-25 17:29:41 +01:00
{
2023-12-22 09:13:45 -05:00
var errMsg = $"Duplicate of emote word {lowerWord} in emotes {emote.ID} and {value.ID}" ;
Log . Error ( errMsg ) ;
2023-01-25 17:29:41 +01:00
continue ;
}
2023-12-22 09:13:45 -05:00
dict . Add ( lowerWord , emote ) ;
2023-01-25 17:29:41 +01:00
}
}
2023-12-22 09:13:45 -05:00
_wordEmoteDict = dict . ToFrozenDictionary ( ) ;
2023-01-25 17:29:41 +01:00
}
/// <summary>
/// Makes selected entity to emote using <see cref="EmotePrototype"/> and sends message to chat.
/// </summary>
/// <param name="source">The entity that is speaking</param>
/// <param name="emoteId">The id of emote prototype. Should has valid <see cref="EmotePrototype.ChatMessages"/></param>
Northstar Gloves (#16021)
* Added Gloves of North Star, no sprite or talking yet...
* Added sprites for the gloves of the north star...
* Replaced more placeholder sprites for northstar gloves...
* Added gloves of the north star to uplink...
* Added speech on hit, not yet configureable
* Not functional yet, but a step in the right direction I hope...
* IT WORKS!!
* Licensing and cleanup
* Reduced attack speed, changed from chat to popup, added some admin logging. It was causing too much adminlog spam otherwise
* Reorganized some files, final build??
* Changed the adminlog type from Verb to new type ItemConfigure
* More cleanup, fix sprite reference maybe
* Keronshb's suggestions, fixed some stuff, made hit sound use the meaty punch sfx
* Adds support for hiding speak/whisper/emote from adminlogs, makes northstar speak again!
* Some file shuffling, some of Keronshb's requests. Might appear a bit funky in github because vscode kept duplicating files for some reason and I had to delete them
* Made it work with the latest changes on Master
* Final? cleanup, upped dmg to 8, made ui not activate on activateinhand, instead you need to right click
* Set value to 0 credits, that's all
* Well that was much easier than I made it out to be. Now you can only activate the gloves with right click, no more mispredicts.
* Update MeleeWeaponSystem.cs
Iunno why this got changed in the first place, but I'm changin it back
* emptycommit
* emptycommit
* The tiny fixening
2023-05-23 11:12:30 -07:00
/// <param name="hideLog">Whether or not this message should appear in the adminlog window</param>
2023-05-04 20:08:08 +01:00
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
2023-01-25 17:29:41 +01:00
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
2023-08-11 22:56:34 -07:00
public void TryEmoteWithChat (
EntityUid source ,
string emoteId ,
ChatTransmitRange range = ChatTransmitRange . Normal ,
bool hideLog = false ,
string? nameOverride = null ,
bool ignoreActionBlocker = false
)
2023-01-25 17:29:41 +01:00
{
if ( ! _prototypeManager . TryIndex < EmotePrototype > ( emoteId , out var proto ) )
return ;
2023-08-18 06:40:10 +10:00
TryEmoteWithChat ( source , proto , range , hideLog : hideLog , nameOverride , ignoreActionBlocker : ignoreActionBlocker ) ;
2023-01-25 17:29:41 +01:00
}
/// <summary>
/// Makes selected entity to emote using <see cref="EmotePrototype"/> and sends message to chat.
/// </summary>
/// <param name="source">The entity that is speaking</param>
/// <param name="emote">The emote prototype. Should has valid <see cref="EmotePrototype.ChatMessages"/></param>
Northstar Gloves (#16021)
* Added Gloves of North Star, no sprite or talking yet...
* Added sprites for the gloves of the north star...
* Replaced more placeholder sprites for northstar gloves...
* Added gloves of the north star to uplink...
* Added speech on hit, not yet configureable
* Not functional yet, but a step in the right direction I hope...
* IT WORKS!!
* Licensing and cleanup
* Reduced attack speed, changed from chat to popup, added some admin logging. It was causing too much adminlog spam otherwise
* Reorganized some files, final build??
* Changed the adminlog type from Verb to new type ItemConfigure
* More cleanup, fix sprite reference maybe
* Keronshb's suggestions, fixed some stuff, made hit sound use the meaty punch sfx
* Adds support for hiding speak/whisper/emote from adminlogs, makes northstar speak again!
* Some file shuffling, some of Keronshb's requests. Might appear a bit funky in github because vscode kept duplicating files for some reason and I had to delete them
* Made it work with the latest changes on Master
* Final? cleanup, upped dmg to 8, made ui not activate on activateinhand, instead you need to right click
* Set value to 0 credits, that's all
* Well that was much easier than I made it out to be. Now you can only activate the gloves with right click, no more mispredicts.
* Update MeleeWeaponSystem.cs
Iunno why this got changed in the first place, but I'm changin it back
* emptycommit
* emptycommit
* The tiny fixening
2023-05-23 11:12:30 -07:00
/// <param name="hideLog">Whether or not this message should appear in the adminlog window</param>
/// <param name="hideChat">Whether or not this message should appear in the chat window</param>
2023-05-04 20:08:08 +01:00
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
2023-01-25 17:29:41 +01:00
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
2023-08-11 22:56:34 -07:00
public void TryEmoteWithChat (
EntityUid source ,
EmotePrototype emote ,
ChatTransmitRange range = ChatTransmitRange . Normal ,
bool hideLog = false ,
string? nameOverride = null ,
bool ignoreActionBlocker = false
)
2023-01-25 17:29:41 +01:00
{
// check if proto has valid message for chat
if ( emote . ChatMessages . Count ! = 0 )
{
2023-08-11 22:56:34 -07:00
// not all emotes are loc'd, but for the ones that are we pass in entity
var action = Loc . GetString ( _random . Pick ( emote . ChatMessages ) , ( "entity" , source ) ) ;
2023-08-18 23:59:23 +10:00
SendEntityEmote ( source , action , range , nameOverride , hideLog : hideLog , checkEmote : false , ignoreActionBlocker : ignoreActionBlocker ) ;
2023-01-25 17:29:41 +01:00
}
// do the rest of emote event logic here
2023-08-11 22:56:34 -07:00
TryEmoteWithoutChat ( source , emote , ignoreActionBlocker ) ;
2023-01-25 17:29:41 +01:00
}
/// <summary>
/// Makes selected entity to emote using <see cref="EmotePrototype"/> without sending any messages to chat.
/// </summary>
2023-08-11 22:56:34 -07:00
public void TryEmoteWithoutChat ( EntityUid uid , string emoteId , bool ignoreActionBlocker = false )
2023-01-25 17:29:41 +01:00
{
if ( ! _prototypeManager . TryIndex < EmotePrototype > ( emoteId , out var proto ) )
return ;
2023-08-11 22:56:34 -07:00
TryEmoteWithoutChat ( uid , proto , ignoreActionBlocker ) ;
2023-01-25 17:29:41 +01:00
}
/// <summary>
/// Makes selected entity to emote using <see cref="EmotePrototype"/> without sending any messages to chat.
/// </summary>
2023-08-11 22:56:34 -07:00
public void TryEmoteWithoutChat ( EntityUid uid , EmotePrototype proto , bool ignoreActionBlocker = false )
2023-01-25 17:29:41 +01:00
{
2023-08-11 22:56:34 -07:00
if ( ! _actionBlocker . CanEmote ( uid ) & & ! ignoreActionBlocker )
2023-01-25 17:29:41 +01:00
return ;
InvokeEmoteEvent ( uid , proto ) ;
}
/// <summary>
/// Tries to find and play relevant emote sound in emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound ( EntityUid uid , EmoteSoundsPrototype ? proto , EmotePrototype emote )
{
return TryPlayEmoteSound ( uid , proto , emote . ID ) ;
}
/// <summary>
/// Tries to find and play relevant emote sound in emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound ( EntityUid uid , EmoteSoundsPrototype ? proto , string emoteId )
{
if ( proto = = null )
return false ;
// try to get specific sound for this emote
if ( ! proto . Sounds . TryGetValue ( emoteId , out var sound ) )
{
// no specific sound - check fallback
sound = proto . FallbackSound ;
if ( sound = = null )
return false ;
}
// if general params for all sounds set - use them
var param = proto . GeneralParams ? ? sound . Params ;
_audio . PlayPvs ( sound , uid , param ) ;
return true ;
}
private void TryEmoteChatInput ( EntityUid uid , string textInput )
{
var actionLower = textInput . ToLower ( ) ;
if ( ! _wordEmoteDict . TryGetValue ( actionLower , out var emote ) )
return ;
InvokeEmoteEvent ( uid , emote ) ;
}
private void InvokeEmoteEvent ( EntityUid uid , EmotePrototype proto )
{
var ev = new EmoteEvent ( proto ) ;
RaiseLocalEvent ( uid , ref ev ) ;
}
}
/// <summary>
/// Raised by chat system when entity made some emote.
/// Use it to play sound, change sprite or something else.
/// </summary>
[ByRefEvent]
public struct EmoteEvent
{
public bool Handled ;
public readonly EmotePrototype Emote ;
public EmoteEvent ( EmotePrototype emote )
{
Emote = emote ;
Handled = false ;
}
}