public void OnNWNXChat() { NWPlayer pc = _nwnxChat.GetSender().Object; string newName = _nwnxChat.GetMessage(); if (!CanHandleChat(pc, newName)) { return; } _nwnxChat.SkipMessage(); NWItem renameItem = pc.GetLocalObject("CRAFT_RENAMING_ITEM_OBJECT"); pc.DeleteLocalInt("CRAFT_RENAMING_ITEM"); pc.DeleteLocalObject("CRAFT_RENAMING_ITEM_OBJECT"); if (!renameItem.IsValid) { pc.SendMessage("Cannot find the item you were renaming."); return; } if (newName.Length < 3 || newName.Length > 64) { pc.SendMessage("Item names must be between 3 and 64 characters long."); return; } renameItem.Name = newName; pc.FloatingText("New name set!"); }
public void OnModuleNWNXChat(NWPlayer sender) { if (!sender.IsPlayer || sender.IsDM) { return; } string message = _nwnxChat.GetMessage().Trim().ToLower(); // If it is double slash (//) treat it as a normal message (this is used by role-players to denote OOC speech) if (message.Substring(0, 2) == "//") { return; } if (message.Substring(0, 1) != "/") { return; } var split = message.Split(' ').ToList(); // Commands with no arguments won't be split, so if we didn't split anything then add the command to the split list manually. if (split.Count <= 0) { split.Add(message); } string command = split[0].Substring(1, split[0].Length - 1); _nwnxChat.SkipMessage(); if (!App.IsKeyRegistered <IChatCommand>("ChatCommand." + command)) { sender.SendMessage(_color.Red("Invalid chat command. Use '/help' to get a list of available commands.")); return; } IChatCommand chatCommand = App.ResolveByInterface <IChatCommand>("ChatCommand." + command); CommandDetailsAttribute attribute = chatCommand.GetType().GetCustomAttribute <CommandDetailsAttribute>(); bool isDM = _auth.IsPCRegisteredAsDM(sender); if (attribute != null && (attribute.Permissions.HasFlag(CommandPermissionType.Player) && sender.IsPlayer || attribute.Permissions.HasFlag(CommandPermissionType.DM) && isDM)) { split.RemoveAt(0); chatCommand.DoAction(sender, split.ToArray()); } else { sender.SendMessage(_color.Red("Invalid chat command. Use '/help' to get a list of available commands.")); } }
public void OnModuleNWNXChat(NWPlayer sender) { string text = _nwnxChat.GetMessage().Trim(); if (!CanHandleChat(sender, text)) { return; } _nwnxChat.SkipMessage(); if (text.Length > 32) { sender.FloatingText("Container names must be 32 characters or less."); return; } sender.SetLocalString("NEW_CONTAINER_NAME", text); sender.SendMessage("New container name received. Please press the 'Next' button in the conversation window."); }
public void OnNWNXChat() { ChatChannelType channel = (ChatChannelType)_nwnxChat.GetChannel(); // So we're going to play with a couple of channels here. // - PlayerTalk, PlayerWhisper, PlayerParty, and PlayerShout are all IC channels. These channels // are subject to emote colouring and language translation. (see below for more info). // - PlayerParty is an IC channel with special behaviour. Those outside of the party but within // range may listen in to the party chat. (see below for more information). // - PlayerShout sends a holocom message server-wide through the DMTell channel. // - PlayerDM echoes back the message received to the sender. bool inCharacterChat = channel == ChatChannelType.PlayerTalk || channel == ChatChannelType.PlayerWhisper || channel == ChatChannelType.PlayerParty || channel == ChatChannelType.PlayerShout; bool messageToDm = channel == ChatChannelType.PlayerDM; if (!inCharacterChat && !messageToDm) { // We don't much care about traffic on the other channels. return; } NWObject sender = _nwnxChat.GetSender(); string message = _nwnxChat.GetMessage(); if (string.IsNullOrWhiteSpace(message)) { // We can't handle empty messages, so skip it. return; } if (ChatCommandService.CanHandleChat(sender, message) || BaseService.CanHandleChat(sender, message) || CraftService.CanHandleChat(sender, message)) { // This will be handled by other services, so just bail. return; } if (channel == ChatChannelType.PlayerDM) { // Simply echo the message back to the player. _nwnxChat.SendMessage((int)ChatChannelType.ServerMessage, "(Sent to DM) " + message, sender, sender); return; } // At this point, every channel left is one we want to manually handle. _nwnxChat.SkipMessage(); // If this is a shout message, and the holonet is disabled, we disallow it. if (channel == ChatChannelType.PlayerShout && sender.IsPC && sender.GetLocalInt("DISPLAY_HOLONET") == FALSE) { NWPlayer player = sender.Object; player.SendMessage("You have disabled the holonet and cannot send this message."); return; } List <ChatComponent> chatComponents; // Quick early out - if we start with "//" or "((", this is an OOC message. if (message.Length >= 2 && (message.Substring(0, 2) == "//" || message.Substring(0, 2) == "((")) { ChatComponent component = new ChatComponent { m_Text = message, m_CustomColour = true, m_ColourRed = 64, m_ColourGreen = 64, m_ColourBlue = 64, m_Translatable = false }; chatComponents = new List <ChatComponent>(); chatComponents.Add(component); } else { if (_emoteStyle.GetEmoteStyle(sender) == EmoteStyle.Regular) { chatComponents = SplitMessageIntoComponents_Regular(message); } else { chatComponents = SplitMessageIntoComponents_Novel(message); } // For any components with colour, set the emote colour. foreach (ChatComponent component in chatComponents) { if (component.m_CustomColour) { component.m_ColourRed = 0; component.m_ColourGreen = 255; component.m_ColourBlue = 0; } } } // Now, depending on the chat channel, we need to build a list of recipients. bool needsAreaCheck = false; float distanceCheck = 0.0f; List <NWObject> recipients = new List <NWObject>(); // The sender always wants to see their own message. recipients.Add(sender); // This is a server-wide holonet message (that receivers can toggle on or off). if (channel == ChatChannelType.PlayerShout) { recipients.AddRange(NWModule.Get().Players.Where(player => player.GetLocalInt("DISPLAY_HOLONET") == TRUE)); recipients.AddRange(App.GetAppState().ConnectedDMs); } // This is the normal party chat, plus everyone within 20 units of the sender. else if (channel == ChatChannelType.PlayerParty) { // Can an NPC use the playerparty channel? I feel this is safe ... NWPlayer player = sender.Object; recipients.AddRange(player.PartyMembers.Cast <NWObject>().Where(x => x != sender)); recipients.AddRange(App.GetAppState().ConnectedDMs); needsAreaCheck = true; distanceCheck = 20.0f; } // Normal talk - 20 units. else if (channel == ChatChannelType.PlayerTalk) { needsAreaCheck = true; distanceCheck = 20.0f; } // Whisper - 4 units. else if (channel == ChatChannelType.PlayerWhisper) { needsAreaCheck = true; distanceCheck = 4.0f; } if (needsAreaCheck) { recipients.AddRange(sender.Area.Objects.Where(obj => obj.IsPC && _.GetDistanceBetween(sender, obj) <= distanceCheck)); recipients.AddRange(App.GetAppState().ConnectedDMs.Where(dm => dm.Area == sender.Area && _.GetDistanceBetween(sender, dm) <= distanceCheck)); } // Now we have a list of who is going to actually receive a message, we need to modify // the message for each recipient then dispatch them. foreach (NWObject obj in recipients.Distinct()) { // Generate the final message as perceived by obj. StringBuilder finalMessage = new StringBuilder(); if (channel == ChatChannelType.PlayerShout) { finalMessage.Append("[Holonet] "); } else if (channel == ChatChannelType.PlayerParty) { finalMessage.Append("[Comms] "); if (obj.IsDM) { // Convenience for DMs - append the party members. finalMessage.Append("{ "); int count = 0; NWPlayer player = sender.Object; List <NWPlayer> partyMembers = player.PartyMembers.ToList(); foreach (NWPlayer otherPlayer in partyMembers) { string name = otherPlayer.Name; finalMessage.Append(name.Substring(0, Math.Min(name.Length, 10))); ++count; if (count >= 3) { finalMessage.Append(", ..."); break; } else if (count != partyMembers.Count) { finalMessage.Append(","); } } finalMessage.Append(" } "); } } SkillType language = _language.GetActiveLanguage(sender); // Wookiees cannot speak any other language (but they can understand them). // Swap their language if they attempt to speak in any other language. CustomRaceType race = (CustomRaceType)_.GetRacialType(sender); if (race == CustomRaceType.Wookiee && language != SkillType.Shyriiwook) { _language.SetActiveLanguage(sender, SkillType.Shyriiwook); language = SkillType.Shyriiwook; } int colour = _language.GetColour(language); byte r = (byte)(colour >> 24 & 0xFF); byte g = (byte)(colour >> 16 & 0xFF); byte b = (byte)(colour >> 8 & 0xFF); if (language != SkillType.Basic) { string languageName = _language.GetName(language); finalMessage.Append(_color.Custom($"[{languageName}] ", r, g, b)); } foreach (ChatComponent component in chatComponents) { string text = component.m_Text; if (component.m_Translatable && language != SkillType.Basic) { text = _language.TranslateSnippetForListener(sender, obj.Object, language, component.m_Text); if (colour != 0) { text = _color.Custom(text, r, g, b); } } if (component.m_CustomColour) { text = _color.Custom(text, component.m_ColourRed, component.m_ColourGreen, component.m_ColourBlue); } finalMessage.Append(text); } // Dispatch the final message - method depends on the original chat channel. // - Shout and party is sent as DMTalk. We do this to get around the restriction that // the PC needs to be in the same area for the normal talk channel. // We could use the native channels for these but the [shout] or [party chat] labels look silly. // - Talk and whisper are sent as-is. ChatChannelType finalChannel = channel; if (channel == ChatChannelType.PlayerShout || channel == ChatChannelType.PlayerParty) { finalChannel = ChatChannelType.DMTalk; } // There are a couple of colour overrides we want to use here. // - One for holonet (shout). // - One for comms (party chat). string finalMessageColoured = finalMessage.ToString(); if (channel == ChatChannelType.PlayerShout) { finalMessageColoured = _color.Custom(finalMessageColoured, 0, 180, 255); } else if (channel == ChatChannelType.PlayerParty) { finalMessageColoured = _color.Orange(finalMessageColoured); } _nwnxChat.SendMessage((int)finalChannel, finalMessageColoured, sender, obj); } }
public void OnModuleNWNXChat(NWPlayer sender) { string originalMessage = _nwnxChat.GetMessage().Trim(); if (!CanHandleChat(sender, originalMessage)) { return; } var split = originalMessage.Split(' ').ToList(); // Commands with no arguments won't be split, so if we didn't split anything then add the command to the split list manually. if (split.Count <= 0) { split.Add(originalMessage); } split[0] = split[0].ToLower(); string command = split[0].Substring(1, split[0].Length - 1); split.RemoveAt(0); _nwnxChat.SkipMessage(); if (!App.IsKeyRegistered <IChatCommand>("ChatCommand." + command)) { sender.SendMessage(_color.Red("Invalid chat command. Use '/help' to get a list of available commands.")); return; } App.ResolveByInterface <IChatCommand>("ChatCommand." + command, chatCommand => { string args = string.Join(" ", split); if (!chatCommand.RequiresTarget) { ProcessChatCommand(chatCommand, sender, null, null, args); } else { string error = chatCommand.ValidateArguments(sender, split.ToArray()); if (!string.IsNullOrWhiteSpace(error)) { sender.SendMessage(error); return; } sender.SetLocalString("CHAT_COMMAND", command); sender.SetLocalString("CHAT_COMMAND_ARGS", args); sender.SendMessage("Please use your 'Chat Command Targeter' feat to select the target of this chat command."); if (_.GetHasFeat((int)CustomFeatType.ChatCommandTargeter, sender) == FALSE || sender.IsDM) { _nwnxCreature.AddFeatByLevel(sender, (int)CustomFeatType.ChatCommandTargeter, 1); if (sender.IsDM) { var qbs = _nwnxPlayer.GetQuickBarSlot(sender, 11); if (qbs.ObjectType == QuickBarSlotType.Empty) { _nwnxPlayer.SetQuickBarSlot(sender, 11, _nwnxQBS.UseFeat((int)CustomFeatType.ChatCommandTargeter)); } } } } }); }