예제 #1
0
    public void UpdateClientChat(string message, ChatChannel channels, bool isOriginator, GameObject recipient)
    {
        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        trySendingTTS(message);

        if (PlayerManager.LocalPlayerScript == null)
        {
            channels = ChatChannel.OOC;
        }

        if (channels != ChatChannel.None)
        {
            // replace action messages with chat bubble
            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Action) || channels.HasFlag(ChatChannel.Examine))
            {
                if (isOriginator)
                {
                    ChatBubbleManager.Instance.ShowAction(Regex.Replace(message, "<.*?>", string.Empty), recipient);
                }
            }

            ChatUI.Instance.AddChatEntry(message);
        }
    }
예제 #2
0
    private void UpdateClientChat(string message, ChatChannel channels)
    {
        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        trySendingTTS(message);

        if (PlayerManager.LocalPlayerScript == null)
        {
            channels = ChatChannel.OOC;
        }

        if (channels != ChatChannel.None)
        {
            // replace action messages with chat bubble
            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Action) || channels.HasFlag(ChatChannel.Examine))
            {
                string cleanMessage = Regex.Replace(message, "<.*?>", string.Empty);
                if (cleanMessage.StartsWith("You"))
                {
                    ChatBubbleManager.ShowAChatBubble(PlayerManager.LocalPlayerScript.transform, Regex.Replace(message, "<.*?>", string.Empty));
                    return;
                }
            }

            ChatUI.Instance.AddChatEntry(message);
        }
    }
예제 #3
0
    private void UpdateClientChat(string message, ChatChannel channels)
    {
        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        trySendingTTS(message);

        if (PlayerManager.LocalPlayerScript == null)
        {
            channels = ChatChannel.OOC;
        }

        if (channels != ChatChannel.None)
        {
            // TODO: remove hardcoded "You" check; chat bubbles should be on their own channel or similar - see issue #5775.

            // replace action messages with chat bubble
            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Action) || channels.HasFlag(ChatChannel.Examine))
            {
                string cleanMessage = Regex.Replace(message, "<.*?>", string.Empty);
                if (cleanMessage.StartsWith("You"))
                {
                    ChatBubbleManager.ShowAction(Regex.Replace(message, "<.*?>", string.Empty));
                    return;
                }
            }

            ChatUI.Instance.AddChatEntry(message);
        }
    }
예제 #4
0
    /// <summary>
    /// Sends a player message to the server.
    /// The message is omitted if too many messages have been sent recently.
    /// The message is shortened if the player has send too many characters recently.
    /// In either case the player will see a warning in their chat log.
    /// </summary>
    /// <param name="message">The player's message.</param>
    /// <param name="selectedChannels">The selected channels, which are simply passed along.</param>
    public void Send(string message, ChatChannel selectedChannels)
    {
        print(numMessages);
        DecayFiltersOverTime();         // Decrease cpm and messages since last having spoken

        // Limit number of messages
        if (numMessages + 1 > numMessageMax || cpm + 1 > cpmMax)
        {
            if (selectedChannels.HasFlag(ChatChannel.OOC) || selectedChannels.HasFlag(ChatChannel.Ghost))
            {
                Chat.AddExamineMsgToClient(numMessagesWarningOOC);
            }
            else
            {
                Chat.AddExamineMsgToClient(numMessagesWarning);
            }
            return;
        }

        // Users message will (at least partiall) be spoken, so count it.
        numMessages++;
        cpm += message.Length;

        // Limit characters per minute
        int numCharsOverLimit = 0;

        if (cpm > cpmMax)
        {
            // Too many characters, calculate how many need to be removed.
            float cpmOver = cpm - cpmMax;
            cpm = cpmMax;             // Characters will be removed, so cpm must be lowered again.
            numCharsOverLimit = (int)Math.Floor(cpmOver);

            message = message.Remove(message.Length - numCharsOverLimit) + "...";
        }

        // Don't send message if it got shortened below the limit.
        if (0 < numCharsOverLimit && numCharsOverLimit < cpmMinCharacters)
        {
            return;
        }

        // Send message, which might have been shortened because of the character limit per minute.
        PostToChatMessage.Send(message, selectedChannels);

        // Notify player that their message got cut short.
        if (numCharsOverLimit > 0)
        {
            if (selectedChannels.HasFlag(ChatChannel.OOC) || selectedChannels.HasFlag(ChatChannel.Ghost))
            {
                Chat.AddExamineMsgToClient(cpmWarningOOC);
            }
            else
            {
                Chat.AddExamineMsgToClient(cpmWarning);
            }
        }
    }
예제 #5
0
 private static bool IsNamelessChan(ChatChannel channel)
 {
     if (channel.HasFlag(ChatChannel.System) ||
         channel.HasFlag(ChatChannel.Combat) ||
         channel.HasFlag(ChatChannel.Action) ||
         channel.HasFlag(ChatChannel.Examine))
     {
         return(true);
     }
     return(false);
 }
예제 #6
0
    private void OnChatInputChanged(string newMsg, ChatChannel selectedChannels)
    {
        if (string.IsNullOrEmpty(newMsg))
        {
            return;
        }

        var hasBlacklistedChannel = BlacklistChannels.HasFlag(selectedChannels);

        if (isPlayerTyping)
        {
            // update last typing time
            lastTypingTime = Time.time;

            // if player was typing before, but changed channel to blacklist channel
            if (hasBlacklistedChannel)
            {
                StopTyping();
            }
        }
        else
        {
            // if player stared typing in allowed channel
            if (!hasBlacklistedChannel)
            {
                StartTyping();
            }
        }
    }
예제 #7
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        var player = sentByPlayer.Script;

        var chatEvent = new ChatEvent
        {
            message    = message,
            modifiers  = (player == null) ? ChatModifier.None : player.GetCurrentChatModifiers(),
            speaker    = player.name,
            position   = ((player == null) ? Vector2.zero : (Vector2)player.gameObject.transform.position),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;
            Instance.addChatLogServer.Invoke(chatEvent);
            return;
        }

        // There could be multiple channels we need to send a message for each.
        // We do this on the server side that local chans can be determined correctly
        foreach (Enum value in Enum.GetValues(channels.GetType()))
        {
            if (channels.HasFlag((ChatChannel)value))
            {
                //Using HasFlag will always return true for flag at value 0 so skip it
                if ((ChatChannel)value == ChatChannel.None)
                {
                    continue;
                }

                if (IsNamelessChan((ChatChannel)value))
                {
                    continue;
                }

                chatEvent.channels = (ChatChannel)value;
                Instance.addChatLogServer.Invoke(chatEvent);
            }
        }
    }
예제 #8
0
    public static List <ChatChannel> getChannelsByMask(ChatChannel channelMask)
    {
        List <ChatChannel> channelsByMask = Enum.GetValues(typeof(ChatChannel))
                                            .Cast <ChatChannel>()
                                            .Where(value => channelMask.HasFlag(value))
                                            .ToList();

        channelsByMask.Remove(ChatChannel.None);
        return(channelsByMask);
    }
예제 #9
0
    private static bool IsOnCorrectChannels(ChatChannel channels)
    {
        if (channels.HasFlag(ChatChannel.Common) ||
            channels.HasFlag(ChatChannel.Command) || channels.HasFlag(ChatChannel.Security) ||
            channels.HasFlag(ChatChannel.Engineering) || channels.HasFlag(ChatChannel.Medical) ||
            channels.HasFlag(ChatChannel.Science) ||
            channels.HasFlag(ChatChannel.Syndicate) || channels.HasFlag(ChatChannel.Supply))
        {
            return(true);
        }

        return(false);
    }
예제 #10
0
    private void UpdatePossibleChannels()
    {
        // get available channels
        ChatChannel chatChannels = ChatUI.Instance.GetAvailableChannels();

        // get all chat channels
        ChatChannel[] allChannels = (ChatChannel[])Enum.GetValues(typeof(ChatChannel));

        StringBuilder newContent = new StringBuilder();

        // start from 4 to skip 'None', 'Examine', 'Local', 'OOC'
        for (int i = 4; i < allChannels.Length; i++)
        {
            ChatChannel channel = allChannels[i];
            // player have access to this channel
            if (chatChannels.HasFlag(channel))
            {
                newContent.Append(GetChannelEntry(channel));
            }
        }

        channelsText.text = newContent.ToString();
    }
예제 #11
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels, Loudness loudness = Loudness.NORMAL)
    {
        message = AutoMod.ProcessChatServer(sentByPlayer, message);
        if (string.IsNullOrWhiteSpace(message))
        {
            return;
        }

        //Sanity check for null username
        if (string.IsNullOrWhiteSpace(sentByPlayer.Username))
        {
            Logger.Log($"Null/empty Username, Details: Username: {sentByPlayer.Username}, ClientID: {sentByPlayer.ClientId}, IP: {sentByPlayer.Connection.address}",
                       Category.Admin);
            return;
        }

        var player = sentByPlayer.Script;

        //Check to see whether this player is allowed to send on the chosen channels
        if (player != null)
        {
            channels &= player.GetAvailableChannelsMask(true);
        }
        else
        {
            //If player is null, must be in lobby therefore lock to OOC
            channels = ChatChannel.OOC;
        }

        if (channels == ChatChannel.None)
        {
            return;
        }

        // The exact words that leave the player's mouth (or that are narrated). Already includes HONKs, stutters, etc.
        // This step is skipped when speaking in the OOC channel.
        (string message, ChatModifier chatModifiers)processedMessage = (string.Empty, ChatModifier.None);          // Placeholder values
        bool isOOC = channels.HasFlag(ChatChannel.OOC);

        if (!isOOC)
        {
            processedMessage = ProcessMessage(sentByPlayer, message);

            if (string.IsNullOrWhiteSpace(processedMessage.message))
            {
                return;
            }
        }

        var chatEvent = new ChatEvent
        {
            message    = isOOC ? message : processedMessage.message,
            modifiers  = (player == null) ? ChatModifier.None : processedMessage.chatModifiers,
            speaker    = (player == null) ? sentByPlayer.Username : player.playerName,
            position   = (player == null) ? TransformState.HiddenPos : player.PlayerChatLocation.AssumedWorldPosServer(),
            channels   = channels,
            originator = (player == null) ? sentByPlayer.GameObject : player.PlayerChatLocation,
            VoiceLevel = loudness
        };

        //This is to make sure OOC doesn't break
        if (sentByPlayer.Job != JobType.NULL)
        {
            CheckVoiceLevel(sentByPlayer.Script, chatEvent.channels);
        }


        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = StripAll(sentByPlayer.Username);

            var isAdmin = PlayerList.Instance.IsAdmin(sentByPlayer.UserId);

            if (isAdmin)
            {
                chatEvent.speaker = "<color=red>[A]</color> " + chatEvent.speaker;
            }
            else if (PlayerList.Instance.IsMentor(sentByPlayer.UserId))
            {
                chatEvent.speaker = "<color=#6400ff>[M]</color> " + chatEvent.speaker;
            }

            if (Instance.OOCMute && !isAdmin)
            {
                return;
            }

            //http/https links in OOC chat
            if (isAdmin || !GameManager.Instance.AdminOnlyHtml)
            {
                if (htmlRegex.IsMatch(chatEvent.message))
                {
                    var messageParts = chatEvent.message.Split(' ');

                    var builder = new StringBuilder();

                    foreach (var part in messageParts)
                    {
                        if (!htmlRegex.IsMatch(part))
                        {
                            builder.Append(part);
                            builder.Append(" ");
                            continue;
                        }

                        builder.Append($"<link={part}><color=blue>{part}</color></link> ");
                    }

                    chatEvent.message = builder.ToString();

                    //TODO have a config file available to whitelist/blacklist links if all players are allowed to post links
                    //disables client side tag protection to allow <link=></link> tag
                    chatEvent.stripTags = false;
                }
            }

            ChatRelay.Instance.PropagateChatToClients(chatEvent);

            var strippedSpeaker = StripTags(chatEvent.speaker);

            //Sends OOC message to a discord webhook
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookOOCURL, message, strippedSpeaker, ServerData.ServerConfig.DiscordWebhookOOCMentionsID);

            if (!ServerData.ServerConfig.DiscordWebhookSendOOCToAllChat)
            {
                return;
            }

            //Send it to All chat
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookAllChatURL, $"[{ChatChannel.OOC}]  {message}\n", strippedSpeaker);

            return;
        }

        // TODO the following code uses player.playerHealth, but ConciousState would be more appropriate.
        // Check if the player is allowed to talk:
        if (player != null)
        {
            if (player.playerHealth != null)
            {
                if (!player.IsDeadOrGhost && player.mind.IsMiming && !processedMessage.chatModifiers.HasFlag(ChatModifier.Emote))
                {
                    AddWarningMsgFromServer(sentByPlayer.GameObject, "You can't talk because you made a vow of silence.");
                    return;
                }

                if (player.playerHealth.IsCrit)
                {
                    if (!player.playerHealth.IsDead)
                    {
                        return;
                    }
                    else
                    {
                        chatEvent.channels = ChatChannel.Ghost;
                    }
                }
                else if (!player.playerHealth.IsDead && !player.IsGhost)
                {
                    //Control the chat bubble
                    player.playerNetworkActions.ServerToggleChatIcon(true, processedMessage.message, channels, processedMessage.chatModifiers);
                }
            }
        }

        InvokeChatEvent(chatEvent);
    }
예제 #12
0
    /// <summary>
    /// Processes message further for the chat log.
    /// Adds text styling, color and channel prefixes depending on the message and its modifiers.
    /// </summary>
    /// <returns>The chat message, formatted to suit the chat log.</returns>
    public static string ProcessMessageFurther(string message, string speaker, ChatChannel channels,
                                               ChatModifier modifiers, bool stripTags = true)
    {
        playedSound = false;
        //Highlight in game name by bolding and underlining if possible
        //Dont play sound here as it could be examine or action, we only play sound for someone speaking
        message = HighlightInGameName(message, false);

        //Skip everything if system message
        if (channels.HasFlag(ChatChannel.System))
        {
            return(message);
        }

        //Skip everything in case of combat channel
        if (channels.HasFlag(ChatChannel.Combat))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));            //POC
        }

        //Skip everything if it is an action or examine message or if it is a local message
        //without a speaker (which is used by machines)
        if (channels.HasFlag(ChatChannel.Examine) ||
            channels.HasFlag(ChatChannel.Action) ||
            channels.HasFlag(ChatChannel.Local) && string.IsNullOrEmpty(speaker))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        // Skip everything if the message is a local warning
        if (channels.HasFlag(ChatChannel.Warning))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        if (stripTags)
        {
            message = StripTags(message);

            //Bold names again after tag stripping
            message = HighlightInGameName(message);
        }

        //Check for emote. If found skip chat modifiers, make sure emote is only in Local channel
        if ((modifiers & ChatModifier.Emote) == ChatModifier.Emote)
        {
            // /me message
            channels = ChatChannel.Local;
            if (playerGameObject != null)
            {
                DoEmoteAction(message, playerGameObject, Instance.emoteActionManager);
                playerGameObject = null;
                return("");
            }

            message = AddMsgColor(channels, $"<i><b>{speaker}</b> {message}</i>");
            return(message);
        }

        //Check for OOC. If selected, remove all other channels and modifiers (could happen if UI f***s up or someone tampers with it)
        if (channels.HasFlag(ChatChannel.OOC))
        {
            //ooc name quick fix
            var name = Regex.Replace(speaker, @"\t\n\r", "");
            if (string.IsNullOrWhiteSpace(name))
            {
                name = "nerd";
            }

            //highlight OOC name by bolding and underlining if possible
            message = HighlightName(message, ServerData.Auth.CurrentUser.DisplayName);

            message = AddMsgColor(channels, $"[ooc] <b>{name}: {message}</b>");
            return(message);
        }

        //Ghosts don't get modifiers
        if (channels.HasFlag(ChatChannel.Ghost))
        {
            string[] _ghostVerbs = { "cries", "moans" };
            return(AddMsgColor(channels, $"[dead] <b>{speaker}</b> {_ghostVerbs.PickRandom()}: {message}"));
        }
        string verb = "says,";

        if ((modifiers & ChatModifier.Mute) == ChatModifier.Mute)
        {
            return("");
        }

        if ((modifiers & ChatModifier.Whisper) == ChatModifier.Whisper)
        {
            verb    = "whispers,";
            message = $"<i>{message}</i>";
        }
        else if ((modifiers & ChatModifier.Sing) == ChatModifier.Sing)
        {
            verb     = "sings,";
            message += " ♫";
        }
        else if ((modifiers & ChatModifier.Yell) == ChatModifier.Yell)
        {
            verb    = "yells,";
            message = $"<b>{message}</b>";
        }
        else if ((modifiers & ChatModifier.State) == ChatModifier.State)
        {
            verb = "states,";
        }
        else if ((modifiers & ChatModifier.ColdlyState) == ChatModifier.ColdlyState)
        {
            verb = " coldly states,";
        }
        else if (message.EndsWith("!"))
        {
            verb = "exclaims,";
        }
        else if (message.EndsWith("?"))
        {
            verb = "asks,";
        }

        var chan = $"[{channels.ToString().ToLower().Substring(0, 3)}] ";

        if (channels.HasFlag(ChatChannel.Command))
        {
            chan = "[cmd] ";
        }

        if (channels.HasFlag(ChatChannel.Local))
        {
            chan = "";
        }

        return(AddMsgColor(channels,
                           $"{chan}<b>{speaker}</b> {verb}" // [cmd]  Username says,
                           + "  "                           // Two hair spaces. This triggers Text-to-Speech.
                           + "\"" + message + "\""));       // "This text will be spoken by TTS!"
    }
예제 #13
0
    private void PropagateChatToClients(ChatEvent chatEvent)
    {
        List <ConnectedPlayer> players = PlayerList.Instance.AllPlayers;

        //Local chat range checks:
        if (chatEvent.channels.HasFlag(ChatChannel.Local) ||
            chatEvent.channels.HasFlag(ChatChannel.Combat) ||
            chatEvent.channels.HasFlag(ChatChannel.Action))
        {
            for (int i = players.Count - 1; i >= 0; i--)
            {
                if (players[i].Script == null)
                {
                    //joined viewer, don't message them
                    players.RemoveAt(i);
                    continue;
                }

                if (players[i].Script.IsGhost)
                {
                    //send all to ghosts
                    continue;
                }

                if (chatEvent.position == TransformState.HiddenPos)
                {
                    //show messages with no provided position to everyone
                    continue;
                }

                var playerPosition = players[i].GameObject.AssumedWorldPosServer();
                if (Vector2.Distance(chatEvent.position, playerPosition) > 14f)
                {
                    //Player in the list is too far away for local chat, remove them:
                    players.RemoveAt(i);
                }
                else
                {
                    //within range, but check if they are in another room or hiding behind a wall
                    if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls
                                               , layerMask, playerPosition).ItHit)
                    {
                        //if it hit a wall remove that player
                        players.RemoveAt(i);
                    }
                }
            }

            //Get NPCs in vicinity
            var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask);
            foreach (Collider2D coll in npcs)
            {
                var npcPosition = coll.gameObject.AssumedWorldPosServer();
                if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls,
                                           layerMask, npcPosition).ItHit == false)
                {
                    //NPC is in hearing range, pass the message on:
                    var mobAi = coll.GetComponent <MobAI>();
                    if (mobAi != null)
                    {
                        mobAi.LocalChatReceived(chatEvent);
                    }
                }
            }
        }

        for (var i = 0; i < players.Count; i++)
        {
            ChatChannel channels = chatEvent.channels;

            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) ||
                channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) ||
                channels.HasFlag(ChatChannel.Action))
            {
                if (!channels.HasFlag(ChatChannel.Binary) || players[i].Script.IsGhost)
                {
                    UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                           chatEvent.originator, chatEvent.speaker);

                    continue;
                }
            }

            if (players[i].Script == null)
            {
                channels &= ChatChannel.OOC;
            }
            else
            {
                channels &= players[i].Script.GetAvailableChannelsMask(false);
            }

            //if the mask ends up being a big fat 0 then don't do anything
            if (channels != ChatChannel.None)
            {
                UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                       chatEvent.originator, chatEvent.speaker);
            }
        }

        if (rconManager != null)
        {
            string name = "";
            if ((namelessChannels & chatEvent.channels) != chatEvent.channels)
            {
                name = "<b>[" + chatEvent.channels + "]</b> ";
            }

            RconManager.AddChatLog(name + chatEvent.message);
        }
    }
예제 #14
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        var player = sentByPlayer.Script;


        var chatEvent = new ChatEvent
        {
            message    = message,
            modifiers  = (player == null) ? ChatModifier.None : player.GetCurrentChatModifiers(),
            speaker    = (player == null) ? sentByPlayer.Username : player.name,
            position   = ((player == null) ? Vector2.zero : (Vector2)player.gameObject.transform.position),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;
            Instance.addChatLogServer.Invoke(chatEvent);
            return;
        }

        //Check if the player is allowed to talk:
        if (player.playerHealth != null)
        {
            if (player.playerHealth.IsCrit || player.playerHealth.IsCardiacArrest)
            {
                if (!player.playerHealth.IsDead)
                {
                    return;
                }
                else
                {
                    channels = ChatChannel.Ghost;
                }
            }
            else
            {
                if (!player.playerHealth.IsDead && !player.IsGhost)
                {
                    {
                        //Control the chat bubble
                        player.playerNetworkActions.CmdToggleChatIcon(true, message, channels);
                    }
                }
            }
        }

        // There could be multiple channels we need to send a message for each.
        // We do this on the server side that local chans can be determined correctly
        foreach (Enum value in Enum.GetValues(channels.GetType()))
        {
            if (channels.HasFlag((ChatChannel)value))
            {
                //Using HasFlag will always return true for flag at value 0 so skip it
                if ((ChatChannel)value == ChatChannel.None)
                {
                    continue;
                }

                if (IsNamelessChan((ChatChannel)value))
                {
                    continue;
                }

                chatEvent.channels = (ChatChannel)value;
                Instance.addChatLogServer.Invoke(chatEvent);
            }
        }
    }
예제 #15
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        var player = sentByPlayer.Script;

        // The exact words that leave the player's mouth (or that are narrated). Already includes HONKs, stutters, etc.
        // This step is skipped when speaking in the OOC channel.
        (string message, ChatModifier chatModifiers)processedMessage = (string.Empty, ChatModifier.None);          // Placeholder values
        bool isOOC = channels.HasFlag(ChatChannel.OOC);

        if (!isOOC)
        {
            processedMessage = ProcessMessage(sentByPlayer, message);
        }

        var chatEvent = new ChatEvent
        {
            message    = isOOC ? message : processedMessage.message,
            modifiers  = (player == null) ? ChatModifier.None : processedMessage.chatModifiers,
            speaker    = (player == null) ? sentByPlayer.Username : player.name,
            position   = ((player == null) ? TransformState.HiddenPos : player.WorldPos),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;
            Instance.addChatLogServer.Invoke(chatEvent);
            return;
        }

        // TODO the following code uses player.playerHealth, but ConciousState would be more appropriate.
        // Check if the player is allowed to talk:
        if (player != null && player.playerHealth != null)
        {
            if (player.playerHealth.IsCrit || player.playerHealth.IsCardiacArrest)
            {
                if (!player.playerHealth.IsDead)
                {
                    return;
                }
                else
                {
                    channels = ChatChannel.Ghost;
                }
            }
            else if (!player.playerHealth.IsDead && !player.IsGhost)
            {
                //Control the chat bubble
                player.playerNetworkActions.CmdToggleChatIcon(true, processedMessage.message, channels, processedMessage.chatModifiers);
            }
        }

        // There could be multiple channels we need to send a message for each.
        // We do this on the server side that local chans can be determined correctly
        foreach (Enum value in Enum.GetValues(channels.GetType()))
        {
            if (channels.HasFlag((ChatChannel)value))
            {
                //Using HasFlag will always return true for flag at value 0 so skip it
                if ((ChatChannel)value == ChatChannel.None)
                {
                    continue;
                }

                if (IsNamelessChan((ChatChannel)value))
                {
                    continue;
                }

                chatEvent.channels = (ChatChannel)value;
                Instance.addChatLogServer.Invoke(chatEvent);
            }
        }
    }
예제 #16
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        message = AutoMod.ProcessChatServer(sentByPlayer, message);
        if (string.IsNullOrWhiteSpace(message))
        {
            return;
        }

        var player = sentByPlayer.Script;

        // The exact words that leave the player's mouth (or that are narrated). Already includes HONKs, stutters, etc.
        // This step is skipped when speaking in the OOC channel.
        (string message, ChatModifier chatModifiers)processedMessage = (string.Empty, ChatModifier.None);          // Placeholder values
        bool isOOC = channels.HasFlag(ChatChannel.OOC);

        if (!isOOC)
        {
            processedMessage = ProcessMessage(sentByPlayer, message);
        }

        var chatEvent = new ChatEvent
        {
            message    = isOOC ? message : processedMessage.message,
            modifiers  = (player == null) ? ChatModifier.None : processedMessage.chatModifiers,
            speaker    = (player == null) ? sentByPlayer.Username : player.name,
            position   = (player == null) ? TransformState.HiddenPos : player.gameObject.AssumedWorldPosServer(),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;

            var isAdmin = PlayerList.Instance.IsAdmin(sentByPlayer.UserId);

            if (isAdmin)
            {
                chatEvent.speaker = "[Admin] " + chatEvent.speaker;
            }

            if (Instance.OOCMute && !isAdmin)
            {
                return;
            }

            Instance.addChatLogServer.Invoke(chatEvent);

            //Sends OOC message to a discord webhook
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookOOCURL, message, chatEvent.speaker, ServerData.ServerConfig.DiscordWebhookOOCMentionsID);

            if (!ServerData.ServerConfig.DiscordWebhookSendOOCToAllChat)
            {
                return;
            }

            //Send it to All chat
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookAllChatURL, $"[{ChatChannel.OOC}]  {message}\n", chatEvent.speaker);

            return;
        }

        // TODO the following code uses player.playerHealth, but ConciousState would be more appropriate.
        // Check if the player is allowed to talk:
        if (player != null && player.playerHealth != null)
        {
            if (!player.IsDeadOrGhost && player.mind.IsMiming && !processedMessage.chatModifiers.HasFlag(ChatModifier.Emote))
            {
                AddWarningMsgFromServer(sentByPlayer.GameObject, "You can't talk because you made a vow of silence.");
                return;
            }

            if (player.playerHealth.IsCrit || player.playerHealth.IsCardiacArrest)
            {
                if (!player.playerHealth.IsDead)
                {
                    return;
                }
                else
                {
                    chatEvent.channels = ChatChannel.Ghost;
                }
            }
            else if (!player.playerHealth.IsDead && !player.IsGhost)
            {
                //Control the chat bubble
                player.playerNetworkActions.CmdToggleChatIcon(true, processedMessage.message, channels, processedMessage.chatModifiers);
            }
        }

        InvokeChatEvent(chatEvent);
    }
예제 #17
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        message = AutoMod.ProcessChatServer(sentByPlayer, message);
        if (string.IsNullOrWhiteSpace(message))
        {
            return;
        }

        var player = sentByPlayer.Script;

        // The exact words that leave the player's mouth (or that are narrated). Already includes HONKs, stutters, etc.
        // This step is skipped when speaking in the OOC channel.
        (string message, ChatModifier chatModifiers)processedMessage = (string.Empty, ChatModifier.None);          // Placeholder values
        bool isOOC = channels.HasFlag(ChatChannel.OOC);

        if (!isOOC)
        {
            processedMessage = ProcessMessage(sentByPlayer, message);
        }

        var chatEvent = new ChatEvent
        {
            message    = isOOC ? message : processedMessage.message,
            modifiers  = (player == null) ? ChatModifier.None : processedMessage.chatModifiers,
            speaker    = (player == null) ? sentByPlayer.Username : player.name,
            position   = (player == null) ? TransformState.HiddenPos : player.gameObject.AssumedWorldPosServer(),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;

            var isAdmin = PlayerList.Instance.IsAdmin(sentByPlayer.UserId);

            if (isAdmin)
            {
                chatEvent.speaker = "<color=red>[Admin]</color> " + chatEvent.speaker;
            }
            else if (PlayerList.Instance.IsMentor(sentByPlayer.UserId))
            {
                chatEvent.speaker = "<color=#6400ff>[Mentor]</color> " + chatEvent.speaker;
            }

            if (Instance.OOCMute && !isAdmin)
            {
                return;
            }

            //http/https links in OOC chat
            if (isAdmin || !GameManager.Instance.AdminOnlyHtml)
            {
                if (htmlRegex.IsMatch(chatEvent.message))
                {
                    var messageParts = chatEvent.message.Split(' ');

                    var builder = new StringBuilder();

                    foreach (var part in messageParts)
                    {
                        if (!htmlRegex.IsMatch(part))
                        {
                            builder.Append(part);
                            builder.Append(" ");
                            continue;
                        }

                        builder.Append($"<link={part}><color=blue>{part}</color></link> ");
                    }

                    chatEvent.message = builder.ToString();

                    //TODO have a config file available to whitelist/blacklist links if all players are allowed to post links
                    //disables client side tag protection to allow <link=></link> tag
                    chatEvent.stripTags = false;
                }
            }

            Instance.addChatLogServer.Invoke(chatEvent);

            //Sends OOC message to a discord webhook
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookOOCURL, message, chatEvent.speaker, ServerData.ServerConfig.DiscordWebhookOOCMentionsID);

            if (!ServerData.ServerConfig.DiscordWebhookSendOOCToAllChat)
            {
                return;
            }

            //Send it to All chat
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookAllChatURL, $"[{ChatChannel.OOC}]  {message}\n", chatEvent.speaker);

            return;
        }

        // TODO the following code uses player.playerHealth, but ConciousState would be more appropriate.
        // Check if the player is allowed to talk:
        if (player != null && player.playerHealth != null)
        {
            if (!player.IsDeadOrGhost && player.mind.IsMiming && !processedMessage.chatModifiers.HasFlag(ChatModifier.Emote))
            {
                AddWarningMsgFromServer(sentByPlayer.GameObject, "You can't talk because you made a vow of silence.");
                return;
            }

            if (player.playerHealth.IsCrit || player.playerHealth.IsCardiacArrest)
            {
                if (!player.playerHealth.IsDead)
                {
                    return;
                }
                else
                {
                    chatEvent.channels = ChatChannel.Ghost;
                }
            }
            else if (!player.playerHealth.IsDead && !player.IsGhost)
            {
                //Control the chat bubble
                player.playerNetworkActions.CmdToggleChatIcon(true, processedMessage.message, channels, processedMessage.chatModifiers);
            }
        }

        InvokeChatEvent(chatEvent);
    }
예제 #18
0
    /// <summary>
    /// Processes message further for the chat log.
    /// Adds text styling, color and channel prefixes depending on the message and its modifiers.
    /// </summary>
    /// <returns>The chat message, formatted to suit the chat log.</returns>
    public static string ProcessMessageFurther(string message, string speaker, ChatChannel channels,
                                               ChatModifier modifiers)
    {
        //Skip everything if system message
        if (channels.HasFlag(ChatChannel.System))
        {
            return(message);
        }

        //Skip everything in case of combat channel
        if (channels.HasFlag(ChatChannel.Combat))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));            //POC
        }

        //Skip everything if it is an action or examine message or if it is a local message
        //without a speaker (which is used by machines)
        if (channels.HasFlag(ChatChannel.Examine) || channels.HasFlag(ChatChannel.Action) ||
            channels.HasFlag(ChatChannel.Local) &&
            string.IsNullOrEmpty(speaker))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        // Skip everything if the message is a local warning
        if (channels.HasFlag(ChatChannel.Warning))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        message = StripTags(message);

        //Check for emote. If found skip chat modifiers, make sure emote is only in Local channel
        if ((modifiers & ChatModifier.Emote) == ChatModifier.Emote)
        {
            // /me message
            channels = ChatChannel.Local;
            message  = AddMsgColor(channels, $"<i><b>{speaker}</b> {message}</i>");
            return(message);
        }

        //Check for OOC. If selected, remove all other channels and modifiers (could happen if UI f***s up or someone tampers with it)
        if (channels.HasFlag(ChatChannel.OOC))
        {
            //ooc name quick fix
            var name = Regex.Replace(speaker, @"\t\n\r", "");
            if (string.IsNullOrWhiteSpace(name))
            {
                name = "nerd";
            }

            message = AddMsgColor(channels, $"[ooc] <b>{speaker}: {message}</b>");
            return(message);
        }

        //Ghosts don't get modifiers
        if (channels.HasFlag(ChatChannel.Ghost))
        {
            string[] _ghostVerbs = { "cries", "moans" };
            return(AddMsgColor(channels, $"[dead] <b>{speaker}</b> {_ghostVerbs.PickRandom()}: {message}"));
        }

        string verb = "says,";

        if ((modifiers & ChatModifier.Mute) == ChatModifier.Mute)
        {
            return("");
        }

        if ((modifiers & ChatModifier.Whisper) == ChatModifier.Whisper)
        {
            verb    = "whispers,";
            message = $"<i>{message}</i>";
        }
        else if ((modifiers & ChatModifier.Sing) == ChatModifier.Sing)
        {
            verb     = "sings,";
            message += " ♫";
        }
        else if ((modifiers & ChatModifier.Yell) == ChatModifier.Yell)
        {
            verb    = "yells,";
            message = $"<b>{message}</b>";
        }
        else if ((modifiers & ChatModifier.State) == ChatModifier.State)
        {
            verb = "states,";
        }
        else if ((modifiers & ChatModifier.ColdlyState) == ChatModifier.ColdlyState)
        {
            verb = "coldly states,";
        }
        else if (message.EndsWith("!"))
        {
            verb = "exclaims,";
        }
        else if (message.EndsWith("?"))
        {
            verb = "asks,";
        }

        var chan = $"[{channels.ToString().ToLower().Substring(0, 3)}] ";

        if (channels.HasFlag(ChatChannel.Command))
        {
            chan = "[cmd] ";
        }

        if (channels.HasFlag(ChatChannel.Local))
        {
            chan = "";
        }

        return(AddMsgColor(channels,
                           $"{chan}<b>{speaker}</b> {verb}" // [cmd] Username says,
                           + "  "                           // Two hair spaces. This triggers Text-to-Speech.
                           + "\"" + message + "\""));       // "This text will be spoken by TTS!"
    }
예제 #19
0
    private void PropagateChatToClients(ChatEvent chatEvent)
    {
        List <ConnectedPlayer> players;

        if (chatEvent.matrix != MatrixInfo.Invalid)
        {
            //get players only on provided matrix
            players = PlayerList.Instance.GetPlayersOnMatrix(chatEvent.matrix);
        }
        else
        {
            players = PlayerList.Instance.AllPlayers;
        }

        //Local chat range checks:
        if (chatEvent.channels == ChatChannel.Local || chatEvent.channels == ChatChannel.Combat ||
            chatEvent.channels == ChatChannel.Action)
        {
            //			var speaker = PlayerList.Instance.Get(chatEvent.speaker);
            LayerMask layerMask = LayerMask.GetMask("Walls", "Door Closed");
            for (int i = 0; i < players.Count(); i++)
            {
                if (players[i].Script == null)
                {
                    //joined viewer, don't message them
                    players.Remove(players[i]);
                    continue;
                }

                if (players[i].Script.IsGhost)
                {
                    //send all to ghosts
                    continue;
                }

                if (Vector2.Distance(chatEvent.position,                 //speaker.GameObject.transform.position,
                                     players[i].GameObject.transform.position) > 14f)
                {
                    //Player in the list is too far away for local chat, remove them:
                    players.Remove(players[i]);
                }
                else
                {
                    //within range, but check if they are in another room or hiding behind a wall
                    if (Physics2D.Linecast(chatEvent.position,                     //speaker.GameObject.transform.position,
                                           players[i].GameObject.transform.position, layerMask))
                    {
                        //if it hit a wall remove that player
                        players.Remove(players[i]);
                    }
                }
            }

            //Get NPCs in vicinity
            var npcMask = LayerMask.GetMask("NPC");
            var npcs    = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask);
            foreach (Collider2D coll in npcs)
            {
                if (!Physics2D.Linecast(chatEvent.position,
                                        coll.transform.position, layerMask))
                {
                    //NPC is in hearing range, pass the message on:
                    var mobAi = coll.GetComponent <MobAI>();
                    if (mobAi != null)
                    {
                        mobAi.LocalChatReceived(chatEvent);
                    }
                }
            }
        }

        for (var i = 0; i < players.Count; i++)
        {
            ChatChannel channels = chatEvent.channels;

            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) ||
                channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) ||
                channels.HasFlag(ChatChannel.Action))
            {
                if (!channels.HasFlag(ChatChannel.Binary) || players[i].Script.IsGhost)
                {
                    UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                           chatEvent.originator, chatEvent.speaker);
                    continue;
                }
            }

            if (players[i].Script == null)
            {
                channels &= ChatChannel.OOC;
            }
            else
            {
                channels &= players[i].Script.GetAvailableChannelsMask(false);
            }

            //if the mask ends up being a big fat 0 then don't do anything
            if (channels != ChatChannel.None)
            {
                UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                       chatEvent.originator, chatEvent.speaker);
            }
        }

        if (RconManager.Instance != null)
        {
            string name = "";
            if ((namelessChannels & chatEvent.channels) != chatEvent.channels)
            {
                name = "<b>[" + chatEvent.channels + "]</b> ";
            }

            RconManager.AddChatLog(name + chatEvent.message);
        }
    }
예제 #20
0
    public void PropagateChatToClients(ChatEvent chatEvent)
    {
        List <ConnectedPlayer> players = PlayerList.Instance.AllPlayers;

        //Local chat range checks:
        if (chatEvent.channels.HasFlag(ChatChannel.Local) ||
            chatEvent.channels.HasFlag(ChatChannel.Combat) ||
            chatEvent.channels.HasFlag(ChatChannel.Action))
        {
            for (int i = players.Count - 1; i >= 0; i--)
            {
                if (players[i].Script == null)
                {
                    //joined viewer, don't message them
                    players.RemoveAt(i);
                    continue;
                }

                if (players[i].Script.gameObject == chatEvent.originator)
                {
                    //Always send the originator chat to themselves
                    continue;
                }

                if (players[i].Script.IsGhost && players[i].Script.IsPlayerSemiGhost == false)
                {
                    //send all to ghosts
                    continue;
                }

                if (chatEvent.position == TransformState.HiddenPos)
                {
                    //show messages with no provided position to everyone
                    continue;
                }

                //Send chat to PlayerChatLocation pos, usually just the player object but for AI is its vessel
                var playerPosition = players[i].Script.PlayerChatLocation.OrNull()?.AssumedWorldPosServer()
                                     ?? players[i].Script.gameObject.AssumedWorldPosServer();

                //Do player position to originator distance check
                if (DistanceCheck(playerPosition) == false)
                {
                    //Distance check failed so if we are Ai, then try send action and combat messages to their camera location
                    //as well as if possible
                    if (chatEvent.channels.HasFlag(ChatChannel.Local) == false &&
                        players[i].Script.PlayerState == PlayerScript.PlayerStates.Ai &&
                        players[i].Script.TryGetComponent <AiPlayer>(out var aiPlayer) &&
                        aiPlayer.IsCarded == false)
                    {
                        playerPosition = players[i].Script.gameObject.AssumedWorldPosServer();

                        //Check camera pos
                        if (DistanceCheck(playerPosition))
                        {
                            //Camera can see player, allow Ai to see action/combat messages
                            continue;
                        }
                    }

                    //Player failed distance checks remove them
                    players.RemoveAt(i);
                }

                bool DistanceCheck(Vector3 playerPos)
                {
                    //TODO maybe change this to (chatEvent.position - playerPos).sqrMagnitude > 196f to avoid square root for performance?
                    if (Vector2.Distance(chatEvent.position, playerPos) > 14f)
                    {
                        //Player in the list is too far away for local chat, remove them:
                        return(false);
                    }

                    //Within range, but check if they are in another room or hiding behind a wall
                    if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls,
                                               layerMask, playerPos).ItHit)
                    {
                        //If it hit a wall remove that player
                        return(false);
                    }

                    //Player can see the position
                    return(true);
                }
            }

            //Get NPCs in vicinity
            var npcs = Physics2D.OverlapCircleAll(chatEvent.position, 14f, npcMask);
            foreach (Collider2D coll in npcs)
            {
                var npcPosition = coll.gameObject.AssumedWorldPosServer();
                if (MatrixManager.Linecast(chatEvent.position, LayerTypeSelection.Walls,
                                           layerMask, npcPosition).ItHit == false)
                {
                    //NPC is in hearing range, pass the message on:
                    var mobAi = coll.GetComponent <MobAI>();
                    if (mobAi != null)
                    {
                        mobAi.LocalChatReceived(chatEvent);
                    }
                }
            }
        }

        for (var i = 0; i < players.Count; i++)
        {
            ChatChannel channels = chatEvent.channels;

            if (channels.HasFlag(ChatChannel.Combat) || channels.HasFlag(ChatChannel.Local) ||
                channels.HasFlag(ChatChannel.System) || channels.HasFlag(ChatChannel.Examine) ||
                channels.HasFlag(ChatChannel.Action))
            {
                //Binary check here to avoid speaking in local when speaking on binary
                if (!channels.HasFlag(ChatChannel.Binary) || (players[i].Script.IsGhost && players[i].Script.IsPlayerSemiGhost == false))
                {
                    UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                           chatEvent.originator, chatEvent.speaker, chatEvent.stripTags);

                    continue;
                }
            }

            if (players[i].Script == null)
            {
                channels &= ChatChannel.OOC;
            }
            else
            {
                channels &= players[i].Script.GetAvailableChannelsMask(false);
            }

            //if the mask ends up being a big fat 0 then don't do anything
            if (channels != ChatChannel.None)
            {
                UpdateChatMessage.Send(players[i].GameObject, channels, chatEvent.modifiers, chatEvent.message, chatEvent.messageOthers,
                                       chatEvent.originator, chatEvent.speaker, chatEvent.stripTags);
            }
        }

        if (rconManager != null)
        {
            string name = "";
            if ((namelessChannels & chatEvent.channels) != chatEvent.channels)
            {
                name = "<b>[" + chatEvent.channels + "]</b> ";
            }

            RconManager.AddChatLog(name + chatEvent.message);
        }
    }
예제 #21
0
    public static string ProcessMessageFurther(string message, string speaker, ChatChannel channels,
                                               ChatModifier modifiers)
    {
        //Skip everything if system message
        if (channels.HasFlag(ChatChannel.System))
        {
            return(message);
        }

        //Skip everything in case of combat channel
        if (channels.HasFlag(ChatChannel.Combat))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));            //POC
        }

        //Skip everything if it is an action or examine message or if it is a local message
        //without a speaker (which is used by machines)
        if (channels.HasFlag(ChatChannel.Examine) || channels.HasFlag(ChatChannel.Action) ||
            channels.HasFlag(ChatChannel.Local) && string.IsNullOrEmpty(speaker))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        // Skip everything if the message is a local warning
        if (channels.HasFlag(ChatChannel.Warning))
        {
            return(AddMsgColor(channels, $"<i>{message}</i>"));
        }

        message = StripTags(message);

        //Check for emote. If found skip chat modifiers, make sure emote is only in Local channel
        Regex rx = new Regex("^(/me )");

        if (rx.IsMatch(message))
        {
            // /me message
            channels = ChatChannel.Local;

            message = rx.Replace(message, " ");
            message = AddMsgColor(channels, $"<i><b>{speaker}</b> {message}</i>");
            return(message);
        }

        //Check for OOC. If selected, remove all other channels and modifiers (could happen if UI f***s up or someone tampers with it)
        if (channels.HasFlag(ChatChannel.OOC))
        {
            message = AddMsgColor(channels, $"[ooc] <b>{speaker}: {message}</b>");
            return(message);
        }

        //Ghosts don't get modifiers
        if (channels.HasFlag(ChatChannel.Ghost))
        {
            return(AddMsgColor(channels, $"[dead] <b>{speaker}</b>: {message}"));
        }

        message = ApplyModifiers(message, modifiers);
        if (message.Length < 1)
        {
            return("");
        }

        var verb         = "says:";
        var toUpperCheck = message.ToUpper(CultureInfo.InvariantCulture);

        if (message.Contains("!") && toUpperCheck != message)
        {
            verb = "exclaims,";
        }

        if (toUpperCheck == message)
        {
            verb    = "yells,";
            message = $"<b>{message}</b>";
        }

        var chan = $"[{channels.ToString().ToLower().Substring(0, 3)}] ";

        if (channels.HasFlag(ChatChannel.Command))
        {
            chan = "[cmd] ";
        }

        if (channels.HasFlag(ChatChannel.Local))
        {
            chan = "";
        }

        return(AddMsgColor(channels, $"{chan}<b>{speaker}</b> {verb} " + "\"" + message + "\""));
    }
예제 #22
0
 private static string GetChannelColor(ChatChannel channel)
 {
     if (channel.HasFlag(ChatChannel.OOC))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.oocColor));
     }
     if (channel.HasFlag(ChatChannel.Ghost))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.ghostColor));
     }
     if (channel.HasFlag(ChatChannel.Binary))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.binaryColor));
     }
     if (channel.HasFlag(ChatChannel.Supply))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.supplyColor));
     }
     if (channel.HasFlag(ChatChannel.CentComm))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.centComColor));
     }
     if (channel.HasFlag(ChatChannel.Command))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.commandColor));
     }
     if (channel.HasFlag(ChatChannel.Common))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.commonColor));
     }
     if (channel.HasFlag(ChatChannel.Engineering))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.engineeringColor));
     }
     if (channel.HasFlag(ChatChannel.Medical))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.medicalColor));
     }
     if (channel.HasFlag(ChatChannel.Science))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.scienceColor));
     }
     if (channel.HasFlag(ChatChannel.Security))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.securityColor));
     }
     if (channel.HasFlag(ChatChannel.Service))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.serviceColor));
     }
     if (channel.HasFlag(ChatChannel.Local))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.localColor));
     }
     if (channel.HasFlag(ChatChannel.Combat))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.combatColor));
     }
     if (channel.HasFlag(ChatChannel.Warning))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.warningColor));
     }
     if (channel.HasFlag(ChatChannel.Blob))
     {
         return(ColorUtility.ToHtmlStringRGBA(Instance.blobColor));
     }
     return(ColorUtility.ToHtmlStringRGBA(Instance.defaultColor));
 }
예제 #23
0
    /// <summary>
    /// Send a Chat Msg from a player to the selected Chat Channels
    /// Server only
    /// </summary>
    public static void AddChatMsgToChat(ConnectedPlayer sentByPlayer, string message, ChatChannel channels)
    {
        message = AutoMod.ProcessChatServer(sentByPlayer, message);
        if (string.IsNullOrWhiteSpace(message))
        {
            return;
        }

        var player = sentByPlayer.Script;

        // The exact words that leave the player's mouth (or that are narrated). Already includes HONKs, stutters, etc.
        // This step is skipped when speaking in the OOC channel.
        (string message, ChatModifier chatModifiers)processedMessage = (string.Empty, ChatModifier.None);          // Placeholder values
        bool isOOC = channels.HasFlag(ChatChannel.OOC);

        if (!isOOC)
        {
            processedMessage = ProcessMessage(sentByPlayer, message);

            if (player.mind.occupation.JobType == JobType.MIME && player.mind.IsMiming &&
                !processedMessage.chatModifiers.HasFlag(ChatModifier.Emote))
            {
                AddWarningMsgFromServer(sentByPlayer.GameObject, "You can't talk because you made a vow of silence.");
                return;
            }
        }

        var chatEvent = new ChatEvent
        {
            message    = isOOC ? message : processedMessage.message,
            modifiers  = (player == null) ? ChatModifier.None : processedMessage.chatModifiers,
            speaker    = (player == null) ? sentByPlayer.Username : player.name,
            position   = ((player == null) ? TransformState.HiddenPos : player.WorldPos),
            channels   = channels,
            originator = sentByPlayer.GameObject
        };

        if (channels.HasFlag(ChatChannel.OOC))
        {
            chatEvent.speaker = sentByPlayer.Username;

            if (PlayerList.Instance.IsAdmin(sentByPlayer.UserId))
            {
                chatEvent.speaker = "[Admin] " + chatEvent.speaker;
            }

            Instance.addChatLogServer.Invoke(chatEvent);

            //Sends OOC message to a discord webhook
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookOOCURL, message, chatEvent.speaker, ServerData.ServerConfig.DiscordWebhookOOCMentionsID);

            //Send it to All chat
            DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookAllChatURL, $"[{ChatChannel.OOC}]  {message}\n", chatEvent.speaker);

            return;
        }

        // TODO the following code uses player.playerHealth, but ConciousState would be more appropriate.
        // Check if the player is allowed to talk:
        if (player != null && player.playerHealth != null)
        {
            if (player.playerHealth.IsCrit || player.playerHealth.IsCardiacArrest)
            {
                if (!player.playerHealth.IsDead)
                {
                    return;
                }
                else
                {
                    channels = ChatChannel.Ghost;
                }
            }
            else if (!player.playerHealth.IsDead && !player.IsGhost)
            {
                //Control the chat bubble
                player.playerNetworkActions.CmdToggleChatIcon(true, processedMessage.message, channels, processedMessage.chatModifiers);
            }
        }

        string discordMessage = "";

        // There could be multiple channels we need to send a message for each.
        // We do this on the server side that local chans can be determined correctly
        foreach (Enum value in Enum.GetValues(channels.GetType()))
        {
            if (channels.HasFlag((ChatChannel)value))
            {
                //Using HasFlag will always return true for flag at value 0 so skip it
                if ((ChatChannel)value == ChatChannel.None)
                {
                    continue;
                }

                if (IsNamelessChan((ChatChannel)value))
                {
                    continue;
                }

                chatEvent.channels = (ChatChannel)value;
                Instance.addChatLogServer.Invoke(chatEvent);

                discordMessage += $"[{chatEvent.channels}]  {message}\n";
            }
        }

        //Sends All Chat messages to a discord webhook
        DiscordWebhookMessage.Instance.AddWebHookMessageToQueue(DiscordWebhookURLs.DiscordWebhookAllChatURL, discordMessage, chatEvent.speaker);
    }