Files
OldThink/Content.Shared/Chat/SharedChatSystem.cs
rhailrake aa8e31fa7e - add: Changeling antagonist (#2)
* Changeling WIP

* UI

* Pointers fix

* Moved out abilities

* Regenerate ability

* Fixed Regenerate ability
Prevent ghosting while regenerating

* Cleanup

* Base lesser form

* Finished Lesser Form && Transform

* Transform Sting

* Blind Sting

* Mute Sting
Added OnExamine on absorbed human

* Hallucination Sting
Changeling Absorb and transfer absorbed entities to absorber

* Cryogenic Sting

* Adrenaline Sacs

* Transform now uses Polymorph

* Armblade, Shield, Armor

* Tentacle Arm ability
Tentacle Gun system

* WIP with bugs

* WiP bugs

* fix implant transfer

* Fixed bugs with shop transfer and actions transfer

* Just in case

* Vi sitter i ventrilo och spelar DotA

* Fixes and proper LesserForm tracking

* !!!!!

* Fixed empty buttons

* WIP Gamerule
Ready - shop

* nerf stun time cause its sucks

* cleaning

* just in case

* Absorb DNA Objective.

* Partial objectives with bugs

* fix

* fix pointer

* Changeling objectives

* Changeling objectives №2

* Admin verb, game rule

* Fixed empty list check
Icons for objectives

* Changeling chat, changeling names etc.

* fix some merge errors

* - fix: Fixed all bugs with changeling

---------

Co-authored-by: Y-Parvus <yevhen.parvus@gmail.com>
Co-authored-by: Y-Parvus <61109031+Y-Parvus@users.noreply.github.com>
Co-authored-by: HitPanda <104197232+EnefFlow@users.noreply.github.com>
Co-authored-by: EnefFlow <regeto90@mail.ru>
2024-01-31 14:01:35 +00:00

230 lines
7.6 KiB
C#

using Content.Shared.Popups;
using Content.Shared.Radio;
using Content.Shared.Speech;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared.Chat;
public abstract class SharedChatSystem : EntitySystem
{
public const char RadioCommonPrefix = ';';
public const char RadioChannelPrefix = ':';
public const char RadioChannelAltPrefix = '.';
public const char LocalPrefix = '>';
public const char ConsolePrefix = '/';
public const char DeadPrefix = '\\';
public const char LOOCPrefix = '(';
public const char OOCPrefix = '[';
public const char EmotesPrefix = '@';
public const char EmotesAltPrefix = '*';
public const char AdminPrefix = ']';
public const char WhisperPrefix = ',';
public const char DefaultChannelKey = 'h';
public const char ChangelingPrefix = '<';
public const char CultPrefix = '^'; // WD EDIT
[ValidatePrototypeId<RadioChannelPrototype>]
public const string CommonChannel = "Common";
public static string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}";
[ValidatePrototypeId<SpeechVerbPrototype>]
public const string DefaultSpeechVerb = "Default";
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
/// <summary>
/// Cache of the keycodes for faster lookup.
/// </summary>
private readonly Dictionary<char, RadioChannelPrototype> _keyCodes = new();
public override void Initialize()
{
base.Initialize();
DebugTools.Assert(_prototypeManager.HasIndex<RadioChannelPrototype>(CommonChannel));
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
CacheRadios();
}
protected virtual void OnPrototypeReload(PrototypesReloadedEventArgs obj)
{
if (obj.WasModified<RadioChannelPrototype>())
CacheRadios();
}
private void CacheRadios()
{
_keyCodes.Clear();
foreach (var proto in _prototypeManager.EnumeratePrototypes<RadioChannelPrototype>())
{
//WD-EDIT
foreach (var keycode in proto.KeyCodes)
{
if (_keyCodes.ContainsKey(keycode))
continue;
_keyCodes.Add(keycode, proto);
}
//WD-EDIT
}
}
/// <summary>
/// Attempts to find an applicable <see cref="SpeechVerbPrototype"/> for a speaking entity's message.
/// If one is not found, returns <see cref="DefaultSpeechVerb"/>.
/// </summary>
public SpeechVerbPrototype GetSpeechVerb(EntityUid source, string message, SpeechComponent? speech = null)
{
if (!Resolve(source, ref speech, false))
return _prototypeManager.Index<SpeechVerbPrototype>(DefaultSpeechVerb);
// check for a suffix-applicable speech verb
SpeechVerbPrototype? current = null;
foreach (var (str, id) in speech.SuffixSpeechVerbs)
{
var proto = _prototypeManager.Index(id);
if (message.EndsWith(Loc.GetString(str)) && proto.Priority >= (current?.Priority ?? 0))
{
current = proto;
}
}
// if no applicable suffix verb return the normal one used by the entity
return current ?? _prototypeManager.Index(speech.SpeechVerb);
}
/// <summary>
/// Attempts to resolve radio prefixes in chat messages (e.g., remove a leading ":e" and resolve the requested
/// channel. Returns true if a radio message was attempted, even if the channel is invalid.
/// </summary>
/// <param name="source">Source of the message</param>
/// <param name="input">The message to be modified</param>
/// <param name="output">The modified message</param>
/// <param name="channel">The channel that was requested, if any</param>
/// <param name="quiet">Whether or not to generate an informative pop-up message.</param>
/// <returns></returns>
public bool TryProccessRadioMessage(
EntityUid source,
string input,
out string output,
out RadioChannelPrototype? channel,
bool quiet = false)
{
output = input.Trim();
channel = null;
if (input.Length == 0)
return false;
if (input.StartsWith(RadioCommonPrefix))
{
output = SanitizeMessageCapital(input[1..].TrimStart());
channel = _prototypeManager.Index<RadioChannelPrototype>(CommonChannel);
return true;
}
if (!(input.StartsWith(RadioChannelPrefix) || input.StartsWith(RadioChannelAltPrefix)))
return false;
if (input.Length < 2 || char.IsWhiteSpace(input[1]))
{
output = SanitizeMessageCapital(input[1..].TrimStart());
if (!quiet)
_popup.PopupEntity(Loc.GetString("chat-manager-no-radio-key"), source, source);
return true;
}
var channelKey = input[1];
channelKey = char.ToLower(channelKey);
output = SanitizeMessageCapital(input[2..].TrimStart());
if (channelKey == DefaultChannelKey)
{
var ev = new GetDefaultRadioChannelEvent();
RaiseLocalEvent(source, ev);
if (ev.Channel != null)
_prototypeManager.TryIndex(ev.Channel, out channel);
return true;
}
if (!_keyCodes.TryGetValue(channelKey, out channel) && !quiet)
{
var msg = Loc.GetString("chat-manager-no-such-channel", ("key", channelKey));
_popup.PopupEntity(msg, source, source);
}
return true;
}
public string SanitizeMessageCapital(string message)
{
if (string.IsNullOrEmpty(message))
return message;
// Capitalize first letter
message = char.ToUpper(message[0]) + message.Remove(0, 1);
return message;
}
public string SanitizeMessageCapitalizeTheWordI(string message, string theWordI = "i")
{
if (string.IsNullOrEmpty(message))
return message;
for
(
var index = message.IndexOf(theWordI);
index != -1;
index = message.IndexOf(theWordI, index + 1)
)
{
// Stops the code If It's tryIng to capItalIze the letter I In the mIddle of words
// Repeating the code twice is the simplest option
if (index + 1 < message.Length && char.IsLetter(message[index + 1]))
continue;
if (index - 1 >= 0 && char.IsLetter(message[index - 1]))
continue;
var beforeTarget = message.Substring(0, index);
var target = message.Substring(index, theWordI.Length);
var afterTarget = message.Substring(index + theWordI.Length);
message = beforeTarget + target.ToUpper() + afterTarget;
}
return message;
}
public static string SanitizeAnnouncement(string message, int maxLength = 0, int maxNewlines = 2)
{
var trimmed = message.Trim();
if (maxLength > 0 && trimmed.Length > maxLength)
{
trimmed = $"{message[..maxLength]}...";
}
// No more than max newlines, other replaced to spaces
if (maxNewlines > 0)
{
var chars = trimmed.ToCharArray();
var newlines = 0;
for (var i = 0; i < chars.Length; i++)
{
if (chars[i] != '\n')
continue;
if (newlines >= maxNewlines)
chars[i] = ' ';
newlines++;
}
return new string(chars);
}
return trimmed;
}
}