diff --git a/Werewolf for Telegram/Database/Group.cs b/Werewolf for Telegram/Database/Group.cs index deaf32e8..0ad60f32 100644 --- a/Werewolf for Telegram/Database/Group.cs +++ b/Werewolf for Telegram/Database/Group.cs @@ -25,6 +25,7 @@ public Group() public int Id { get; set; } public string Name { get; set; } public long GroupId { get; set; } + public Nullable GroupTopicId { get; set; } public Nullable Preferred { get; set; } public string Language { get; set; } public Nullable DisableNotification { get; set; } diff --git a/Werewolf for Telegram/Database/WerewolfModel.edmx b/Werewolf for Telegram/Database/WerewolfModel.edmx index 74ef243a..d360ef31 100644 --- a/Werewolf for Telegram/Database/WerewolfModel.edmx +++ b/Werewolf for Telegram/Database/WerewolfModel.edmx @@ -178,6 +178,7 @@ + @@ -884,6 +885,7 @@ warning 6002: The table/view 'werewolf.dbo.v_IdleKill24HoursMain' does not have + @@ -1664,6 +1666,7 @@ warning 6002: The table/view 'werewolf.dbo.v_IdleKill24HoursMain' does not have + @@ -2176,4 +2179,4 @@ warning 6002: The table/view 'werewolf.dbo.v_IdleKill24HoursMain' does not have - \ No newline at end of file + diff --git a/Werewolf for Telegram/Languages/English.xml b/Werewolf for Telegram/Languages/English.xml index c9a49f61..15532fe1 100644 --- a/Werewolf for Telegram/Languages/English.xml +++ b/Werewolf for Telegram/Languages/English.xml @@ -2269,5 +2269,19 @@ As you were preparing your kerosene and lighter, a gust of wind blew in from the doorway, causing you to freeze 🐺☃️. The snow wolf was here! But if you know one thing, it is that ice can be beaten by fire. Standing right next to one of the numerous candles in your house, you feel how its heat thaws you, allowing you to move. Nothing can stop your fire! 🔥 + + + ❌ You must run this command inside a topic/thread (not the general topic). + + + ✅ Group topic has been set successfully. + + + 🗑️ Group topic has been unset. + + + + This command can only be used in the configured topic/thread. (Topic id : {0}) + diff --git a/Werewolf for Telegram/Werewolf Control/Attributes/Command.cs b/Werewolf for Telegram/Werewolf Control/Attributes/Command.cs index 9c897e3e..1718bb35 100644 --- a/Werewolf for Telegram/Werewolf Control/Attributes/Command.cs +++ b/Werewolf for Telegram/Werewolf Control/Attributes/Command.cs @@ -44,5 +44,10 @@ public class Command : Attribute /// Can this command be run by anonymous admins in groups /// public bool AllowAnonymousAdmins { get; set; } = false; + + /// + /// Allow commands to be run outside configured topic in group. + /// + public bool AllowOutsideConfiguredTopic { get; set; } = false; } } diff --git a/Werewolf for Telegram/Werewolf Control/Commands/AdminCommands.cs b/Werewolf for Telegram/Werewolf Control/Commands/AdminCommands.cs index 2674466a..a9169830 100644 --- a/Werewolf for Telegram/Werewolf Control/Commands/AdminCommands.cs +++ b/Werewolf for Telegram/Werewolf Control/Commands/AdminCommands.cs @@ -1,4 +1,4 @@ -using Database; +using Database; using Newtonsoft.Json; using System; using System.Collections; @@ -23,6 +23,60 @@ namespace Werewolf_Control { public static partial class Commands { + [Attributes.Command(Trigger = "settopic", GroupAdminOnly = true, InGroupOnly = true)] + public static void SetTopic(Update update, string[] args) + { + long chatId = update.Message.Chat.Id; + int? topicId = update.Message.MessageThreadId; + + // TODO: allow general topic? some group may use general topic for game. + if (topicId == null) + { + Bot.Send(GetLocaleString("SetTopicCmdNotInGeneral",GetLanguage(chatId)).ToBold(), chatId, messageThreadId: 0); + return; + } + + using (var db = new WWContext()) + { + var group = db.Groups.FirstOrDefault(g => g.GroupId == chatId); + if (group == null) + { + group = MakeDefaultGroup(chatId, update.Message.Chat.Title, "settopic_cmd"); + db.Groups.Add(group); + } + + group.GroupTopicId = topicId; + Helpers.Bot.ChatTopicIdCache[chatId] = topicId; + db.SaveChanges(); + } + + Bot.Send(GetLocaleString("SetTopicSuccess",GetLanguage(chatId)).ToBold(), chatId, messageThreadId: topicId.Value); + } + + [Attributes.Command(Trigger = "remtopic", GroupAdminOnly = true, InGroupOnly = true)] + public static void RemoveTopic(Update update, string[] args) + { + long chatId = update.Message.Chat.Id; + int? topicId = update.Message.MessageThreadId; + + using (var db = new WWContext()) + { + var group = db.Groups.FirstOrDefault(g => g.GroupId == chatId); + if (group == null) + { + group = MakeDefaultGroup(chatId, update.Message.Chat.Title, "remtopic_cmd"); + db.Groups.Add(group); + } + + group.GroupTopicId = null; + Helpers.Bot.ChatTopicIdCache[chatId] = null; + db.SaveChanges(); + } + + Bot.Send(GetLocaleString("SetTopicSuccess", GetLanguage(chatId)).ToBold(), chatId, messageThreadId: topicId ?? 0); + } + + [Attributes.Command(Trigger = "smite", GroupAdminOnly = true, Blockable = true, InGroupOnly = true, AllowAnonymousAdmins = true)] public static void Smite(Update u, string[] args) { diff --git a/Werewolf for Telegram/Werewolf Control/Commands/GameCommands.cs b/Werewolf for Telegram/Werewolf Control/Commands/GameCommands.cs index 6a2bea18..3d72e7e1 100644 --- a/Werewolf for Telegram/Werewolf Control/Commands/GameCommands.cs +++ b/Werewolf for Telegram/Werewolf Control/Commands/GameCommands.cs @@ -186,7 +186,8 @@ public static void Extend(Update update, string[] args) } } - [Command(Trigger = "stopwaiting", Blockable = true)] + // allowing outside topic, as it doesn't response into topic command was ran. dm user that their next game notification is turned off + [Command(Trigger = "stopwaiting", Blockable = true, AllowOutsideConfiguredTopic = true)] public static void StopWaiting(Update update, string[] args) { long groupid = 0; diff --git a/Werewolf for Telegram/Werewolf Control/Commands/GeneralCommands.cs b/Werewolf for Telegram/Werewolf Control/Commands/GeneralCommands.cs index c2f97589..6f40ebed 100644 --- a/Werewolf for Telegram/Werewolf Control/Commands/GeneralCommands.cs +++ b/Werewolf for Telegram/Werewolf Control/Commands/GeneralCommands.cs @@ -179,9 +179,9 @@ public static void SetLang(Update update, string[] args) var curLangFileName = GetLanguage(update.Message.From.Id); var curLang = langs.First(x => x.FileName == curLangFileName); Bot.Api.SendTextMessageAsync(chatId: update.Message.From.Id, text: GetLocaleString("WhatLang", curLangFileName, curLang.Base), - replyMarkup: menu); + replyMarkup: menu, messageThreadId: update.Message.MessageThreadId); if (update.Message.Chat.Type != ChatType.Private) - Send(GetLocaleString("SentPrivate", GetLanguage(update.Message.From.Id)), update.Message.Chat.Id); + Send(GetLocaleString("SentPrivate", GetLanguage(update.Message.From.Id)), update.Message.Chat.Id, messageThreadId: update.Message.MessageThreadId); } [Command(Trigger = "start")] @@ -581,7 +581,7 @@ public static void MyIdles(Update update, string[] args) try { - var result = Bot.Api.SendTextMessageAsync(chatId: update.Message.From.Id, text: reply).Result; + var result = Bot.Api.SendTextMessageAsync(chatId: update.Message.From.Id, text: reply, messageThreadId: update.Message.MessageThreadId).Result; if (update.Message.Chat.Type != ChatType.Private) Send(GetLocaleString("SentPrivate", GetLanguage(update.Message.From.Id)), update.Message.Chat.Id); } diff --git a/Werewolf for Telegram/Werewolf Control/Commands/GifCommands.cs b/Werewolf for Telegram/Werewolf Control/Commands/GifCommands.cs index 0493f4fd..a4a7ed40 100644 --- a/Werewolf for Telegram/Werewolf Control/Commands/GifCommands.cs +++ b/Werewolf for Telegram/Werewolf Control/Commands/GifCommands.cs @@ -28,7 +28,7 @@ public static void Donate(Update u, string[] args) { // Donations disabled as of 2024-06-08 var link = $"currently disabled"; - Bot.Api.SendTextMessageAsync(chatId: u.Message.Chat.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true).Wait(); + Bot.Api.SendTextMessageAsync(chatId: u.Message.Chat.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true, messageThreadId: u.Message.MessageThreadId).Wait(); return; //Bot.Api.SendTextMessageAsync(u.Message.Chat.Id, @@ -106,7 +106,7 @@ public static void SetCustomGifs(Update u, string[] args) "\n\n" + "PLEASE NOTE: Changing any gifs will automatically remove the approval for your pack, and an admin will need to approve it again\n" + "Let's begin! Select the situation you want to set a gif for", - replyMarkup: GetGifMenu(data)); + replyMarkup: GetGifMenu(data), messageThreadId: u.Message.MessageThreadId); var msg = "Current Approval Status:\n"; switch (data.Approved) @@ -123,7 +123,7 @@ public static void SetCustomGifs(Update u, string[] args) msg += "Disapproved By " + dby.Name + " for: " + data.DenyReason; break; } - Bot.Send(msg, u.Message.From.Id); + Bot.Send(msg, u.Message.From.Id, messageThreadId: u.Message.MessageThreadId); } } @@ -304,7 +304,7 @@ public static void RequestGif(CallbackQuery q) Bot.Api.SendTextMessageAsync(chatId: q.From.Id, text: q.Data.Split('|')[1] + "\nOk, send me the GIF you want to use for this situation, as a reply\n" + "#" + choice, - replyMarkup: new ForceReplyMarkup()); + replyMarkup: new ForceReplyMarkup(), messageThreadId: q.Message.MessageThreadId); } public static void AddGif(Message m) @@ -337,14 +337,14 @@ public static void AddGif(Message m) "users are unable to view them, we require you to use telegram's " + "[new GIFs in .mp4 format](https://telegram.org/blog/gif-revolution). " + "To fix this, try reuploading the GIF, your telegram app should then render it as .mp4. " + - "Please send me the GIF you want to use for this situation, as a reply\n#" + gifchoice, replyMarkup: new ForceReplyMarkup(), parseMode: ParseMode.Markdown); + "Please send me the GIF you want to use for this situation, as a reply\n#" + gifchoice, replyMarkup: new ForceReplyMarkup(), parseMode: ParseMode.Markdown, messageThreadId: m.MessageThreadId); return; } if (m.Animation.FileSize >= 1048576) // Maximum size is 1 MB { Bot.Api.SendTextMessageAsync(chatId: m.From.Id, text: "This GIF is too large, the maximum allowed size is 1MB.\n\n" + "Please send me the GIF you want to use for this situation, as a reply\n#" + gifchoice, - replyMarkup: new ForceReplyMarkup()); + replyMarkup: new ForceReplyMarkup(), messageThreadId: m.MessageThreadId); return; } @@ -431,7 +431,7 @@ public static void GetXsollaLink(CallbackQuery q = null, Message m = null) { // Donations disabled as of 2024-06-08 var link = $"currently disabled"; - Bot.Api.SendTextMessageAsync(chatId: (q?.Message ?? m).Chat.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true).Wait(); + Bot.Api.SendTextMessageAsync(chatId: (q?.Message ?? m).Chat.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true, messageThreadId: (q?.Message ?? m).MessageThreadId).Wait(); return; var from = q?.From ?? m?.From; @@ -465,13 +465,13 @@ public static void GetDonationInfo(CallbackQuery q = null, Message m = null) { // Donations disabled as of 2024-06-08 var link = $"currently disabled"; - Bot.Api.SendTextMessageAsync(chatId: q?.From.Id ?? m.From.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true).Wait(); + Bot.Api.SendTextMessageAsync(chatId: q?.From.Id ?? m.From.Id, text: $"Donations are {link}, sorry!", parseMode: ParseMode.Html, disableWebPagePreview: true, messageThreadId: q.Message.MessageThreadId).Wait(); return; var menu = new Menu(); Bot.Api.SendTextMessageAsync(chatId: q?.From.Id ?? m.From.Id, text: "How much would you like to donate? Please enter a whole number, in US Dollars (USD), in reply to this message", - replyMarkup: new ForceReplyMarkup()); + replyMarkup: new ForceReplyMarkup(), messageThreadId: (q?.Message ?? m).MessageThreadId); } public static void ValidateDonationAmount(Message m) @@ -488,14 +488,14 @@ public static void ValidateDonationAmount(Message m) var api = RegHelper.GetRegValue("MainStripeProdAPI"); #endif Bot.Api.SendInvoiceAsync(chatId: m.From.Id, title: "Werewolf Donation", description: "Make a donation to Werewolf to help keep us online", payload: "somepayloadtest", providerToken: api, - currency: "USD", prices: new[] { new LabeledPrice("Donation", amt * 100) }, startParameter: "donatetg").Wait(); + currency: "USD", prices: new[] { new LabeledPrice("Donation", amt * 100) }, startParameter: "donatetg", messageThreadId: m.MessageThreadId).Wait(); } else { Bot.Api.SendTextMessageAsync(chatId: m.From.Id, text: "Invalid input.\n" + "How much would you like to donate? Please enter a whole number, in US Dollars (USD), in reply to this message", - replyMarkup: new ForceReplyMarkup()); + replyMarkup: new ForceReplyMarkup(), messageThreadId: m.MessageThreadId); } } diff --git a/Werewolf for Telegram/Werewolf Control/Commands/Helpers.cs b/Werewolf for Telegram/Werewolf Control/Commands/Helpers.cs index 2d199537..7a98c31b 100644 --- a/Werewolf for Telegram/Werewolf Control/Commands/Helpers.cs +++ b/Werewolf for Telegram/Werewolf Control/Commands/Helpers.cs @@ -170,9 +170,9 @@ private static void StartGame(GameMode gameMode, Update update) } } - internal static Task Send(string message, long id, bool clearKeyboard = false, InlineKeyboardMarkup customMenu = null) + internal static Task Send(string message, long id, bool clearKeyboard = false, InlineKeyboardMarkup customMenu = null, Nullable messageThreadId = null) { - return Bot.Send(message, id, clearKeyboard, customMenu); + return Bot.Send(message, id, clearKeyboard, customMenu, messageThreadId: messageThreadId); } diff --git a/Werewolf for Telegram/Werewolf Control/Handlers/UpdateHandler.cs b/Werewolf for Telegram/Werewolf Control/Handlers/UpdateHandler.cs index 82d4ed35..8506146c 100644 --- a/Werewolf for Telegram/Werewolf Control/Handlers/UpdateHandler.cs +++ b/Werewolf for Telegram/Werewolf Control/Handlers/UpdateHandler.cs @@ -438,6 +438,33 @@ internal static void HandleUpdate(Update update) id); return; } + // If command is not allow outside topic, or it is not admin / dev command. Check topic id and restrict to topic. + if (!(command.AllowOutsideConfiguredTopic || command.GlobalAdminOnly || command.LangAdminOnly || command.DevOnly) ) + { + // Only apply this restriction in groups (topics are only meaningful in groups) + if (update.Message.Chat.Type == ChatType.Group || update.Message.Chat.Type == ChatType.Supergroup) + { + int? currentTopicId; + if (Bot.ChatTopicIdCache.ContainsKey(id)) + currentTopicId = Bot.ChatTopicIdCache[id]; + else + using (var db = new WWContext()) + { + currentTopicId = db.Groups + .Where(g => g.GroupId == id) + .Select(g => g.GroupTopicId) + .FirstOrDefault(); + } + + // If a specific topic is set for the group and this message is NOT in that topic + if (currentTopicId != update.Message.MessageThreadId) + { + Bot.Send(GetLocaleString("MustRunInConfiguredTopic", GetLanguage(id), currentTopicId), id, messageThreadId: update.Message.MessageThreadId ?? 0); + return; + } + } + } + Bot.CommandsReceived++; command.Method.Invoke(update, args); } @@ -824,26 +851,30 @@ internal static void HandleCallback(CallbackQuery query) var id = query.From.Id; Send($"Sending gifs for {pid}", id); Thread.Sleep(1000); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.CultWins), caption: "Cult Wins"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.LoversWin), caption: "Lovers Win"); + // TODO: make Send() work with document also + + int? topicId = DB.Groups.FirstOrDefault(g => g.Id == id).GroupTopicId; + + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.CultWins), caption: "Cult Wins", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.LoversWin), caption: "Lovers Win", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.NoWinner), caption: "No Winner"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.SerialKillerWins), caption: "SK Wins"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.NoWinner), caption: "No Winner", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.SerialKillerWins), caption: "SK Wins", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.StartChaosGame), caption: "Chaos Start"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.StartGame), caption: "Normal Start"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.StartChaosGame), caption: "Chaos Start", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.StartGame), caption: "Normal Start", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.TannerWin), caption: "Tanner Wins"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.VillagerDieImage), caption: "Villager Eaten"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.TannerWin), caption: "Tanner Wins", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.VillagerDieImage), caption: "Villager Eaten", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.VillagersWin), caption: "Village Wins"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.WolfWin), caption: "Single Wolf Wins"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.VillagersWin), caption: "Village Wins", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.WolfWin), caption: "Single Wolf Wins", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.WolvesWin), caption: "Wolf new InputFileId(pack.Wins)"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.SKKilled), caption: "SK Killed"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.WolvesWin), caption: "Wolf new InputFileId(pack.Wins)", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.SKKilled), caption: "SK Killed", messageThreadId: topicId); Thread.Sleep(250); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.ArsonistWins), caption: "Arsonist Wins"); - Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.BurnToDeath), caption: "Arsonist Burnt"); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.ArsonistWins), caption: "Arsonist Wins", messageThreadId: topicId); + Bot.Api.SendDocumentAsync(chatId: id, document: new InputFileId(pack.BurnToDeath), caption: "Arsonist Burnt", messageThreadId: topicId); Thread.Sleep(500); var msg = $"Approval Status: "; switch (pack.Approved) diff --git a/Werewolf for Telegram/Werewolf Control/Helpers/Bot.cs b/Werewolf for Telegram/Werewolf Control/Helpers/Bot.cs index 055ab05c..29e8732b 100644 --- a/Werewolf for Telegram/Werewolf Control/Helpers/Bot.cs +++ b/Werewolf for Telegram/Werewolf Control/Helpers/Bot.cs @@ -32,6 +32,7 @@ internal static class Bot public static User Me; public static DateTime StartTime = DateTime.UtcNow; public static bool Running = true; + public static Dictionary ChatTopicIdCache = new Dictionary(); public static long CommandsReceived = 0; public static long MessagesProcessed = 0; public static long MessagesReceived = 0; @@ -102,6 +103,7 @@ public static void Initialize(string updateid = null) c.InGroupOnly = ca.InGroupOnly; c.LangAdminOnly = ca.LangAdminOnly; c.AllowAnonymousAdmins = ca.AllowAnonymousAdmins; + c.AllowOutsideConfiguredTopic = ca.AllowOutsideConfiguredTopic; Commands.Add(c); } } @@ -513,6 +515,24 @@ internal static Task Send(string message, long id, bool clearKeyboard = { //MessagesSent++; //message = message.Replace("`",@"\`"); + + // Try to load GroupTopicId from the database if no thread ID is provided, with caching + if (messageThreadId == null) + { + if (ChatTopicIdCache.ContainsKey(id)) + messageThreadId = ChatTopicIdCache[id]; + else + using (var db = new WWContext()) + { + var group = db.Groups.FirstOrDefault(g => g.GroupId == id); + if (group?.GroupTopicId != null) + { + messageThreadId = group.GroupTopicId; + ChatTopicIdCache[id] = messageThreadId; + } + } + } + if (clearKeyboard) { //var menu = new ReplyKeyboardRemove() { RemoveKeyboard = true }; diff --git a/Werewolf for Telegram/Werewolf Control/Helpers/LanguageHelper.cs b/Werewolf for Telegram/Werewolf Control/Helpers/LanguageHelper.cs index b1a3f0d4..ddb0f07a 100644 --- a/Werewolf for Telegram/Werewolf Control/Helpers/LanguageHelper.cs +++ b/Werewolf for Telegram/Werewolf Control/Helpers/LanguageHelper.cs @@ -109,7 +109,7 @@ public static void ValidateFiles(long id, int msgId, int? messageThreadId, strin result += "\n"; } - Bot.Api.SendTextMessageAsync(chatId: id, text: result, parseMode: ParseMode.Markdown); + Bot.Api.SendTextMessageAsync(chatId: id, text: result, parseMode: ParseMode.Markdown, messageThreadId: messageThreadId); var sortedfiles = Directory.GetFiles(Bot.LanguageDirectory).Select(x => new LangFile(x)).Where(x => x.Base == (choice ?? x.Base)).OrderBy(x => x.LatestUpdate); result = $"*Validation complete*\nErrors: {errors.Count(x => x.Level == ErrorLevel.Error)}\nMissing strings: {errors.Count(x => x.Level == ErrorLevel.MissingString)}"; result += $"\nMost recently updated file: {sortedfiles.Last().FileName}.xml ({sortedfiles.Last().LatestUpdate.ToString("MMM dd")})\nLeast recently updated file: {sortedfiles.First().FileName}.xml ({sortedfiles.First().LatestUpdate.ToString("MMM dd")})"; diff --git a/Werewolf for Telegram/Werewolf Control/Models/Command.cs b/Werewolf for Telegram/Werewolf Control/Models/Command.cs index effbf14e..6b78de58 100644 --- a/Werewolf for Telegram/Werewolf Control/Models/Command.cs +++ b/Werewolf for Telegram/Werewolf Control/Models/Command.cs @@ -19,5 +19,6 @@ class Command public bool InGroupOnly { get; set; } public bool LangAdminOnly { get; set; } public bool AllowAnonymousAdmins { get; set; } + public bool AllowOutsideConfiguredTopic { get; set; } } } diff --git a/Werewolf for Telegram/Werewolf Node/Program.cs b/Werewolf for Telegram/Werewolf Node/Program.cs index 9aec7ff3..06391be9 100644 --- a/Werewolf for Telegram/Werewolf Node/Program.cs +++ b/Werewolf for Telegram/Werewolf Node/Program.cs @@ -380,23 +380,24 @@ public static void RemoveGame(Werewolf werewolf) } } - internal static async Task Send(string message, long id, bool clearKeyboard = false, InlineKeyboardMarkup customMenu = null, Werewolf game = null, bool notify = false, bool preview = false) + internal static async Task Send(string message, long id, bool clearKeyboard = false, InlineKeyboardMarkup customMenu = null, Werewolf game = null, bool notify = false, bool preview = false, int? messageThreadId = null) { //MessagesSent++; //message = message.FormatHTML(); //message = message.Replace("`",@"\`"); + if (clearKeyboard) { var menu = new ReplyKeyboardRemove(); - return await Bot.SendTextMessageAsync(chatId: id, text: message, replyMarkup: menu, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify); + return await Bot.SendTextMessageAsync(chatId: id, text: message, replyMarkup: menu, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify, messageThreadId: messageThreadId); } else if (customMenu != null) { - return await Bot.SendTextMessageAsync(chatId: id, text: message, replyMarkup: customMenu, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify); + return await Bot.SendTextMessageAsync(chatId: id, text: message, replyMarkup: customMenu, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify, messageThreadId: messageThreadId); } else { - return await Bot.SendTextMessageAsync(chatId: id, text: message, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify); + return await Bot.SendTextMessageAsync(chatId: id, text: message, disableWebPagePreview: !preview, parseMode: ParseMode.Html, disableNotification: notify, messageThreadId: messageThreadId); } } diff --git a/Werewolf for Telegram/Werewolf Node/Werewolf.cs b/Werewolf for Telegram/Werewolf Node/Werewolf.cs index bb9c57fc..3ea6cd3b 100644 --- a/Werewolf for Telegram/Werewolf Node/Werewolf.cs +++ b/Werewolf for Telegram/Werewolf Node/Werewolf.cs @@ -23,6 +23,7 @@ namespace Werewolf_Node public class Werewolf : IDisposable { public long ChatId; + public int? TopicId; public int GameDay, GameId; private int _secondsToAdd = 0; public List Players = new List(); @@ -148,6 +149,7 @@ public Werewolf(long chatid, User u, string chatGroup, GameMode gameMode) // ignored } AllowNSFW = DbGroup.HasFlag(GroupConfig.AllowNSFW); + TopicId = DbGroup.GroupTopicId; var player = db.Players.FirstOrDefault(x => x.TelegramId == u.Id); if (player?.CustomGifSet != null) @@ -231,9 +233,9 @@ public Werewolf(long chatid, User u, string chatGroup, GameMode gameMode) case GameMode.Chaos: FirstMessage = GetLocaleString("PlayerStartedChaosGame", u.FirstName); #if RELEASE - _joinMsgId = Program.Bot.SendDocumentAsync(chatId: ChatId, document: new InputFileId(GetRandomImage(StartChaosGame)), caption: FirstMessage, replyMarkup: _joinButton).Result.MessageId; + _joinMsgId = Program.Bot.SendDocumentAsync(chatId: ChatId, document: new InputFileId(GetRandomImage(StartChaosGame)), caption: FirstMessage, replyMarkup: _joinButton, messageThreadId: TopicId).Result.MessageId; #else - _joinMsgId = Program.Bot.SendTextMessageAsync(chatId: chatid, text: $"\u200C{FirstMessage.FormatHTML()}", replyMarkup: _joinButton, parseMode: ParseMode.Html).Result.MessageId; + _joinMsgId = Program.Bot.SendTextMessageAsync(chatId: chatid, text: $"\u200C{FirstMessage.FormatHTML()}", replyMarkup: _joinButton, parseMode: ParseMode.Html, messageThreadId: TopicId).Result.MessageId; #endif break; @@ -241,9 +243,9 @@ public Werewolf(long chatid, User u, string chatGroup, GameMode gameMode) default: FirstMessage = GetLocaleString("PlayerStartedGame", u.FirstName); #if RELEASE - _joinMsgId = Program.Bot.SendDocumentAsync(chatId: ChatId, document: new InputFileId(GetRandomImage(StartGame)), caption: FirstMessage, replyMarkup: _joinButton).Result.MessageId; + _joinMsgId = Program.Bot.SendDocumentAsync(chatId: ChatId, document: new InputFileId(GetRandomImage(StartGame)), caption: FirstMessage, replyMarkup: _joinButton, messageThreadId: TopicId).Result.MessageId; #else - _joinMsgId = Program.Bot.SendTextMessageAsync(chatId: chatid, text: $"\u200C{FirstMessage.FormatHTML()}", replyMarkup: _joinButton, parseMode: ParseMode.Html).Result.MessageId; + _joinMsgId = Program.Bot.SendTextMessageAsync(chatId: chatid, text: $"\u200C{FirstMessage.FormatHTML()}", replyMarkup: _joinButton, parseMode: ParseMode.Html, messageThreadId: TopicId).Result.MessageId; #endif break; } @@ -259,7 +261,7 @@ public Werewolf(long chatid, User u, string chatGroup, GameMode gameMode) while (ex.InnerException != null) ex = ex.InnerException; - Program.Send("Hmm.. something went wrong, please try starting the game again...\n" + ex.Message, chatid); + Send("Hmm.. something went wrong, please try starting the game again...\n" + ex.Message, chatid); #if DEBUG Send(ex.StackTrace); #else @@ -469,7 +471,7 @@ private void GameTimer() if (i == Settings.GameJoinTime - s) { var str = s == 60 ? GetLocaleString("MinuteLeftToJoin") : GetLocaleString("SecondsLeftToJoin", s.ToString().ToBold()); - r = Program.Bot.SendTextMessageAsync(chatId: ChatId, text: str, parseMode: ParseMode.Html, replyMarkup: _joinButton).Result; + r = Program.Bot.SendTextMessageAsync(chatId: ChatId, text: str, parseMode: ParseMode.Html, replyMarkup: _joinButton, messageThreadId: TopicId).Result; break; } } @@ -485,7 +487,7 @@ private void GameTimer() _secondsToAdd > 0 ? "SecondsAdded" : "SecondsRemoved", Math.Abs(_secondsToAdd).ToString().ToBold(), TimeSpan.FromSeconds(Settings.GameJoinTime - i).ToString(@"mm\:ss").ToBold() - ), parseMode: ParseMode.Html, replyMarkup: _joinButton + ), parseMode: ParseMode.Html, replyMarkup: _joinButton, messageThreadId: TopicId ).Result; _secondsToAdd = 0; @@ -1162,28 +1164,35 @@ public void HandleReply(CallbackQuery query) } } - private Task Send(string message, long id = 0, bool clearKeyboard = false, InlineKeyboardMarkup menu = null, bool notify = false, bool preview = false) + private Task Send(string message, long id = 0, bool clearKeyboard = false, InlineKeyboardMarkup menu = null, bool notify = false, bool preview = false, bool isPlayerDM = false, int? messageThreadId = null) { if (id == 0) id = ChatId; - return Program.Send(message, id, clearKeyboard, menu, game: this, notify: notify, preview: preview); + if (messageThreadId == null) + messageThreadId = TopicId; + + return Program.Send(message, id, clearKeyboard, menu, game: this, notify: notify, preview: preview, messageThreadId: messageThreadId); } private void SendGif(string text, string image, long id = 0) { //Program.MessagesSent++; + bool isPlayerDM = false; if (id == 0) id = ChatId; + else + isPlayerDM = true; + //Log.WriteLine($"{id} -> {image} {text}"); if (!String.IsNullOrWhiteSpace(image)) #if RELEASE - Program.Bot.SendDocumentAsync(chatId: id, document: new InputFileId(image), caption: text); + Program.Bot.SendDocumentAsync(chatId: id, document: new InputFileId(image), caption: text, messageThreadId: TopicId); #else - Send($"\u200C{text}", id, preview: true); + Send($"\u200C{text}", id, preview: true, isPlayerDM: isPlayerDM ); #endif else - Send(text, id, preview: false); + Send(text, id, preview: false, isPlayerDM: isPlayerDM); } private void SendWithQueue(string text, string gif = null, bool requestPM = false) @@ -1421,7 +1430,7 @@ public void OutputPlayers() LastPlayersOutput = DateTime.Now; try { - Program.Bot.SendTextMessageAsync(chatId: ChatId, text: GetLocaleString(_playerListId != 0 ? "LatestList" : "UnableToGetList"), parseMode: ParseMode.Html, replyToMessageId: _playerListId); + Program.Bot.SendTextMessageAsync(chatId: ChatId, text: GetLocaleString(_playerListId != 0 ? "LatestList" : "UnableToGetList"), parseMode: ParseMode.Html, replyToMessageId: _playerListId, messageThreadId: TopicId); } catch { } } @@ -1433,7 +1442,7 @@ public async void ShowJoinButton() LastJoinButtonShowed = DateTime.Now; try { - var r = await Program.Bot.SendTextMessageAsync(chatId: ChatId, text: GetLocaleString("JoinByButton"), parseMode: ParseMode.Html, replyMarkup: _joinButton); + var r = await Program.Bot.SendTextMessageAsync(chatId: ChatId, text: GetLocaleString("JoinByButton"), parseMode: ParseMode.Html, replyMarkup: _joinButton, messageThreadId: TopicId); _joinButtons.Add(r.MessageId); } catch @@ -1626,7 +1635,7 @@ private void NotifyRoles() try { // ReSharper disable once UnusedVariable - var result = Program.Send(msg, p.Id, true).Result; + var result = Send(msg, p.Id, true).Result; } catch (AggregateException ae) { @@ -4984,7 +4993,7 @@ private void SendMenu(List choices, IPlayer to, string t try { - var result = Program.Send(text, to.Id, false, menu).Result; + var result = Send(text, to.Id, false, menu).Result; msgId = result.MessageId; } catch (AggregateException ex) diff --git a/werewolf.sql b/werewolf.sql index c5a35041..aedefa5e 100644 --- a/werewolf.sql +++ b/werewolf.sql @@ -381,6 +381,7 @@ CREATE TABLE [dbo].[Group]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](max) NOT NULL, [GroupId] [bigint] NOT NULL, + [GroupTopicId] [int] NULL, [Preferred] [bit] NULL, [Language] [nvarchar](max) NULL, [DisableNotification] [bit] NULL,