Browse Source

opening random packs

Tigran 3 years ago
parent
commit
860f09ae41
29 changed files with 559 additions and 79 deletions
  1. 3 3
      CardCollector.sln.DotSettings.user
  2. 1 0
      CardCollector/Bot.cs
  3. 19 0
      CardCollector/Commands/CallbackQuery/AuthorMenuQuery.cs
  4. 10 0
      CardCollector/Commands/CallbackQuery/CallbackQuery.cs
  5. 33 0
      CardCollector/Commands/CallbackQuery/DailyTasksQuery.cs
  6. 32 0
      CardCollector/Commands/CallbackQuery/MyPacksQuery.cs
  7. 17 0
      CardCollector/Commands/CallbackQuery/OpenPackCallback.cs
  8. 63 0
      CardCollector/Commands/CallbackQuery/OpenRandomQuery.cs
  9. 6 1
      CardCollector/Commands/CallbackQuery/PutForAuctionQuery.cs
  10. 1 1
      CardCollector/Commands/Message/TextMessage/StopBot.cs
  11. 5 0
      CardCollector/Controllers/AuctionController.cs
  12. 2 0
      CardCollector/DailyTasks/DailyTask.cs
  13. 2 0
      CardCollector/DataBase/CardCollectorDatabase.cs
  14. 1 1
      CardCollector/DataBase/Entity/AuctionEntity.cs
  15. 18 0
      CardCollector/DataBase/Entity/PackEntity.cs
  16. 21 0
      CardCollector/DataBase/Entity/UsersPacksEntity.cs
  17. 6 0
      CardCollector/DataBase/EntityDao/DailyTaskDao.cs
  18. 29 0
      CardCollector/DataBase/EntityDao/PacksDao.cs
  19. 1 1
      CardCollector/DataBase/EntityDao/StickerDao.cs
  20. 40 0
      CardCollector/DataBase/EntityDao/UsersPacksDao.cs
  21. 16 0
      CardCollector/Extensions.cs
  22. 53 35
      CardCollector/Resources/Command.Designer.cs
  23. 35 29
      CardCollector/Resources/Command.resx
  24. 1 1
      CardCollector/Resources/Constants.cs
  25. 7 2
      CardCollector/Resources/Keyboard.cs
  26. 73 1
      CardCollector/Resources/Messages.Designer.cs
  27. 25 1
      CardCollector/Resources/Messages.resx
  28. 29 2
      CardCollector/Resources/Text.Designer.cs
  29. 10 1
      CardCollector/Resources/Text.resx

+ 3 - 3
CardCollector.sln.DotSettings.user

@@ -11,13 +11,13 @@
 	
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FDailyTasks_002FTitles/@EntryIndexedValue">False</s:Boolean>
 	
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FCommand/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FCommand/@EntryIndexedValue">False</s:Boolean>
 	
 	
 	
 	
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FMessages/@EntryIndexedValue">False</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FMessages/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FSortingTypes/@EntryIndexedValue">False</s:Boolean>
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FText/@EntryIndexedValue">False</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FText/@EntryIndexedValue">True</s:Boolean>
 	
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>

+ 1 - 0
CardCollector/Bot.cs

@@ -76,6 +76,7 @@ namespace CardCollector
             var users = await UserDao.GetAllWhere(user => Task.FromResult(!user.IsBlocked));
             foreach (var user in users)
                 await SendMessage(user, Messages.daily_task_alertation);
+            Utilities.SetUpTimer(Constants.DailyTaskAlert, DailyTaskAlert);
         }
     }
 }

+ 19 - 0
CardCollector/Commands/CallbackQuery/AuthorMenuQuery.cs

@@ -0,0 +1,19 @@
+using System.Threading.Tasks;
+using CardCollector.DataBase.Entity;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class AuthorMenuQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.author_menu;
+        public override async Task Execute()
+        {
+            
+        }
+
+        public AuthorMenuQuery() { }
+        public AuthorMenuQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 10 - 0
CardCollector/Commands/CallbackQuery/CallbackQuery.cs

@@ -63,6 +63,16 @@ namespace CardCollector.Commands.CallbackQuery
             new DeleteCombine(),
             /* Команда удаления из комбинации */
             new CombineStickers(),
+            /* Команда которая позволяет пользователю просмотреть паки */
+            new MyPacksQuery(),
+            /* Показывает меню по автору */
+            new AuthorMenuQuery(),
+            /* Открытие рандомного пака */
+            new OpenRandomQuery(),
+            /* Открытие пака автора */
+            new OpenPackCallback(),
+            /* Команда которая показывает список ежедневных заданий */
+            new DailyTasksQuery(),
             //команда подтверждения выставления на аукцион
             new ConfirmationSellingQuery(),
             /* Отмена в момент выбора "значения фильтра", не в самом меню */

+ 33 - 0
CardCollector/Commands/CallbackQuery/DailyTasksQuery.cs

@@ -0,0 +1,33 @@
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DailyTasks;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class DailyTasksQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.daily_tasks;
+        
+        public override async Task Execute()
+        {
+            await User.ClearChat();
+            var text = Messages.your_daily_tasks;
+            var userTasks = await DailyTaskDao.GetUserTasks(User.Id);
+            foreach (var (key, task) in DailyTask.List)
+            {
+                if (!userTasks.ContainsKey((int)key)) 
+                    userTasks.Add((int)key, await DailyTaskDao.AddNew(User.Id, (int)key));
+                text += $"\n{task.Title} ({task.Goal - userTasks[(int) key].Progress}/{task.Goal})";
+            }
+            var message = await MessageController.SendMessage(User, text);
+            User.Session.Messages.Add(message.MessageId);
+        }
+
+        public DailyTasksQuery() { }
+        public DailyTasksQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 32 - 0
CardCollector/Commands/CallbackQuery/MyPacksQuery.cs

@@ -0,0 +1,32 @@
+using System.Linq;
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class MyPacksQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.my_packs;
+        
+        public override async Task Execute()
+        {
+            await User.ClearChat();
+            var userPacks = await UsersPacksDao.GetUserPacks(User.Id);
+            var randomCount = (await UsersPacksDao.GetPackInfo(User.Id, 0)).Count;
+            var authorCount = userPacks.Sum(pack => pack.PackId != 0 ? pack.Count : 0);
+            var message = await MessageController.SendMessage(User, 
+                $"{Messages.your_packs}" +
+                $"\n{Messages.random_packs} {randomCount}{Text.items}" +
+                $"\n{Messages.author_packs} {authorCount}{Text.items}",
+                Keyboard.PackMenu);
+            User.Session.Messages.Add(message.MessageId);
+        }
+
+        public MyPacksQuery() { }
+        public MyPacksQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 17 - 0
CardCollector/Commands/CallbackQuery/OpenPackCallback.cs

@@ -0,0 +1,17 @@
+using System.Threading.Tasks;
+using CardCollector.Resources;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class OpenPackCallback : CallbackQuery
+    {
+        protected override string CommandText => Command.open_pack;
+        
+        public override async Task Execute()
+        {
+            await User.ClearChat();
+            var packId = int.Parse(CallbackData.Split("=")[1]);
+            
+        }
+    }
+}

+ 63 - 0
CardCollector/Commands/CallbackQuery/OpenRandomQuery.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class OpenRandomQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.open_random;
+
+        public override async Task Execute()
+        {
+            var pack = await UsersPacksDao.GetPackInfo(User.Id, 0);
+            if (pack.Count < 1)
+                await MessageController.AnswerCallbackQuery(User, CallbackQueryId, Messages.packs_count_zero, true);
+            else
+            {
+                await User.ClearChat();
+                pack.Count--;
+                var rnd = new Random();
+                var tier = GetTier(rnd.NextDouble() * 100);
+                var stickers = await StickerDao.GetListWhere(item => item.Tier == tier);
+                var sticker = stickers[rnd.Next(stickers.Count)];
+                if (User.Stickers.ContainsKey(sticker.Md5Hash))
+                {
+                    await MessageController.AnswerCallbackQuery(User, CallbackQueryId,
+                        $"{Messages.you_collected} {await User.Cash.Payout(User.Stickers)}");
+                    User.Stickers[sticker.Md5Hash].Count++;
+                }
+                else
+                    await UserStickerRelationDao.AddNew(User, sticker, 1);
+
+                var stickerMessage = await MessageController.SendSticker(User, sticker.Id);
+                var message = await MessageController.SendMessage(User, $"{Messages.congratulation}\n{sticker}");
+                User.Session.Messages.Add(stickerMessage.MessageId);
+                User.Session.Messages.Add(message.MessageId);
+            }
+        }
+
+        private int GetTier(double chance)
+        {
+            return chance switch
+            {
+                < 0.7 => 4,
+                < 3.3 => 3,
+                < 16 => 2,
+                _ => 1
+            };
+        }
+
+        public OpenRandomQuery()
+        {
+        }
+
+        public OpenRandomQuery(UserEntity user, Update update) : base(user, update)
+        {
+        }
+    }
+}

+ 6 - 1
CardCollector/Commands/CallbackQuery/PutForAuctionQuery.cs

@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Linq;
+using System.Threading.Tasks;
 using CardCollector.Commands.Message.TextMessage;
 using CardCollector.Controllers;
 using CardCollector.DataBase.Entity;
@@ -14,10 +15,14 @@ namespace CardCollector.Commands.CallbackQuery
 
         public override async Task Execute()
         {
+            await MessageController.AnswerCallbackQuery(User, CallbackQueryId,
+                Messages.comission_warning, true);
             await User.ClearChat();
             var module = User.Session.GetModule<CollectionModule>();
+            var lowerPrice = (await AuctionController.GetPriceList(module.SelectedSticker.Id)).Min();
             var message = await MessageController.SendMessage(User,
                 $"{Messages.current_price} {module.SellPrice}{Text.gem}" +
+                $"\n{Messages.lower_price} {lowerPrice}{Text.gem}" +
                 $"\n{Messages.enter_your_gems_price} {Text.gem}:", Keyboard.AuctionPutCancelKeyboard);
             EnterGemsPriceMessage.AddToQueue(User.Id, message.MessageId);
             User.Session.Messages.Add(message.MessageId);

+ 1 - 1
CardCollector/Commands/Message/TextMessage/StopBot.cs

@@ -8,7 +8,7 @@ namespace CardCollector.Commands.Message.TextMessage
 {
     public class StopBot : Message
     {
-        protected override string CommandText => Command.stop_bot;
+        protected override string CommandText => Text.stop_bot;
         
         public override async Task Execute()
         {

+ 5 - 0
CardCollector/Controllers/AuctionController.cs

@@ -43,6 +43,11 @@ namespace CardCollector.Controllers
             return await AuctionDao.GetProducts(stickerId);
         }
 
+        public static async Task<IEnumerable<int>> GetPriceList(string stickerId)
+        {
+            return (await AuctionDao.GetProducts(stickerId)).Select(item => item.Price);
+        }
+
         public static async Task<int> GetStickerCount(int productId)
         {
             return await AuctionDao.GetQuantity(productId);

+ 2 - 0
CardCollector/DailyTasks/DailyTask.cs

@@ -3,6 +3,7 @@ using System.Threading.Tasks;
 using System.Timers;
 using CardCollector.DailyTasks.CustomTasks;
 using CardCollector.DataBase.EntityDao;
+using CardCollector.Resources;
 
 namespace CardCollector.DailyTasks
 {
@@ -29,6 +30,7 @@ namespace CardCollector.DailyTasks
         {
             await foreach (var item in DailyTaskDao.GetAll())
                 item.Progress = List[(DailyTaskKeys) item.TaskId].Goal;
+            Utilities.SetUpTimer(Constants.DailyTaskReset, ResetTasks);
         }
     }
 }

+ 2 - 0
CardCollector/DataBase/CardCollectorDatabase.cs

@@ -64,6 +64,8 @@ namespace CardCollector.DataBase
         public DbSet<AuctionEntity> Auction { get; set; }
         public DbSet<ShopEntity> Shop { get; set; }
         public DbSet<DailyTaskEntity> DailyTasks { get; set; }
+        public DbSet<UsersPacksEntity> UsersPacks { get; set; }
+        public DbSet<PackEntity> Packs { get; set; }
 
         
         /* Конфигурация подключения к БД */

+ 1 - 1
CardCollector/DataBase/Entity/AuctionEntity.cs

@@ -30,7 +30,7 @@ namespace CardCollector.DataBase.Entity
             Count -= count;
             var user = await UserDao.GetById(Trader);
             var sticker = await StickerDao.GetById(StickerId);
-            var gemsSum = Price * count;
+            var gemsSum = (int)(Price * count * 0.7);
             await MessageController.SendMessage(user, $"{Messages.you_sold} {sticker.Title} {count}{Text.items}" +
                                                       $"\n{Messages.you_collected} {gemsSum}{Text.gem}");
             user.Cash.Gems += gemsSum;

+ 18 - 0
CardCollector/DataBase/Entity/PackEntity.cs

@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace CardCollector.DataBase.Entity
+{
+    [Table("packs")]
+    public class PackEntity
+    {
+        /* Id набора */
+        [Column("id"), MaxLength(32)] public int Id { get; set; }
+        
+        /* Имя автора */
+        [Column("author"), MaxLength(127)] public string Author { get; set; }
+        
+        /* Описание */
+        [Column("description"), MaxLength(512)] public string Description { get; set; }
+    }
+}

+ 21 - 0
CardCollector/DataBase/Entity/UsersPacksEntity.cs

@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace CardCollector.DataBase.Entity
+{
+    [Table("users_packs")]
+    public class UsersPacksEntity
+    {
+        /* Id записи в таблице, роли не играет */
+        [Column("id"), MaxLength(127)] public long Id { get; set; }
+        
+        /* Id комплекта */
+        [Column("pack_id"), MaxLength(32)] public int PackId { get; set; }
+        
+        /* Id пользователя */
+        [Column("user_id"), MaxLength(127)] public long UserId { get; set; }
+        
+        /* Количество паков у пользователя */
+        [Column("count"), MaxLength(32)] public int Count { get; set; }
+    }
+}

+ 6 - 0
CardCollector/DataBase/EntityDao/DailyTaskDao.cs

@@ -38,5 +38,11 @@ namespace CardCollector.DataBase.EntityDao
             return await Table.FirstOrDefaultAsync(item => item.UserId == userId && item.TaskId == taskId) 
                    ?? await AddNew(userId, taskId);
         }
+
+        public static async Task<Dictionary<int, DailyTaskEntity>> GetUserTasks(long userId)
+        {
+            return (await Table.WhereAsync(item => Task.FromResult(item.UserId == userId)))
+                .ToDictionary(p => p.TaskId, p => p);
+        }
     }
 }

+ 29 - 0
CardCollector/DataBase/EntityDao/PacksDao.cs

@@ -0,0 +1,29 @@
+using System.Threading.Tasks;
+using CardCollector.DataBase.Entity;
+using Microsoft.EntityFrameworkCore;
+
+namespace CardCollector.DataBase.EntityDao
+{
+    public static class PacksDao
+    {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(PacksDao));
+        private static readonly DbSet<PackEntity> Table = Instance.Packs;
+
+        public static async Task<PackEntity> GetById(int id)
+        {
+            return await Table.FirstOrDefaultAsync(item => item.Id == id);
+        }
+        
+        public static async Task<PackEntity> AddNew(string author, string description = "")
+        {
+            var result = await Table.AddAsync(new PackEntity
+            {
+                Author = author,
+                Description = description
+            });
+            await Instance.SaveChangesAsync();
+            return result.Entity;
+        }
+        
+    }
+}

+ 1 - 1
CardCollector/DataBase/EntityDao/StickerDao.cs

@@ -42,7 +42,7 @@ namespace CardCollector.DataBase.EntityDao
 
         public static async Task<List<StickerEntity>> GetListWhere(Func<StickerEntity, bool> func)
         {
-            return (await Table.ToListAsync()).Where(func).ToList();
+            return (await Table.WhereAsync(func)).ToList();
         }
 
         public static async Task<StickerEntity> GetById(string id)

+ 40 - 0
CardCollector/DataBase/EntityDao/UsersPacksDao.cs

@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using CardCollector.DataBase.Entity;
+using Microsoft.EntityFrameworkCore;
+
+namespace CardCollector.DataBase.EntityDao
+{
+    public static class UsersPacksDao
+    {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(UsersPacksDao));
+        private static readonly DbSet<UsersPacksEntity> Table = Instance.UsersPacks;
+
+        public static async Task<List<UsersPacksEntity>> GetUserPacks(long userId)
+        {
+            return (await Table.WhereAsync(item => Task.FromResult(item.UserId == userId))).ToList();
+        }
+
+        public static async Task<UsersPacksEntity> GetPackInfo(long userId, int packId)
+        {
+            return await Table.FirstOrDefaultAsync(item => item.UserId == userId && item.PackId == packId)
+                   ?? await AddNew(userId, packId);
+        }
+
+        public static async Task<UsersPacksEntity> AddNew(long userId, int packId, int count = 0)
+        {
+            if (await Table.FirstOrDefaultAsync(item => item.UserId == userId && item.PackId == packId) is { } obj)
+                return obj;
+            var newPack = new UsersPacksEntity()
+            {
+                PackId = packId,
+                UserId = userId,
+                Count = count
+            };
+            var result = await Table.AddAsync(newPack);
+            await Instance.SaveChangesAsync();
+            return result.Entity;
+        }
+    }
+}

+ 16 - 0
CardCollector/Extensions.cs

@@ -1,11 +1,14 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
 using CardCollector.DataBase.Entity;
 using CardCollector.DataBase.EntityDao;
 using CardCollector.Resources;
+using Microsoft.EntityFrameworkCore;
 using Telegram.Bot.Types.InlineQueryResults;
 
 namespace CardCollector
@@ -73,6 +76,19 @@ namespace CardCollector
             await Task.WhenAll(tasks);
             return results;
         }
+
+        public static async Task<IEnumerable<TSource>> WhereAsync<TSource>(
+            [NotNull] this IQueryable<TSource> source, 
+            [NotNull] Func<TSource, bool> predicate,
+            CancellationToken cancellationToken = default)
+        {
+            var results = new ConcurrentQueue<TSource>();
+            await foreach (var element in source.AsAsyncEnumerable().WithCancellation(cancellationToken))
+            {
+                if (predicate(element)) results.Enqueue(element);
+            }
+            return results;
+        }
         
         public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> source)
         {

+ 53 - 35
CardCollector/Resources/Command.Designer.cs

@@ -72,6 +72,15 @@ namespace CardCollector.Resources {
         /// <summary>
         ///   Looks up a localized string similar to AAB.
         /// </summary>
+        internal static string author_menu {
+            get {
+                return ResourceManager.GetString("author_menu", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to AAC.
+        /// </summary>
         internal static string back {
             get {
                 return ResourceManager.GetString("back", resourceCulture);
@@ -79,7 +88,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAC.
+        ///   Looks up a localized string similar to AAD.
         /// </summary>
         internal static string back_to_combine {
             get {
@@ -88,7 +97,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAD.
+        ///   Looks up a localized string similar to AAE.
         /// </summary>
         internal static string back_to_sticker {
             get {
@@ -97,7 +106,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAE.
+        ///   Looks up a localized string similar to AAF.
         /// </summary>
         internal static string buy_sticker {
             get {
@@ -106,7 +115,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAF.
+        ///   Looks up a localized string similar to AAG.
         /// </summary>
         internal static string cancel {
             get {
@@ -115,7 +124,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAG.
+        ///   Looks up a localized string similar to AAH.
         /// </summary>
         internal static string clear_chat {
             get {
@@ -124,7 +133,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAH.
+        ///   Looks up a localized string similar to AAI.
         /// </summary>
         internal static string collect_income {
             get {
@@ -133,7 +142,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAI.
+        ///   Looks up a localized string similar to AAJ.
         /// </summary>
         internal static string combine {
             get {
@@ -142,7 +151,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAJ.
+        ///   Looks up a localized string similar to AAK.
         /// </summary>
         internal static string combine_stickers {
             get {
@@ -169,7 +178,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ABD.
+        ///   Looks up a localized string similar to AAN.
         /// </summary>
         internal static string control_panel {
             get {
@@ -178,7 +187,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAN.
+        ///   Looks up a localized string similar to AAO.
         /// </summary>
         internal static string count {
             get {
@@ -187,7 +196,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ABE.
+        ///   Looks up a localized string similar to AAP.
         /// </summary>
         internal static string daily_tasks {
             get {
@@ -196,7 +205,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAO.
+        ///   Looks up a localized string similar to AAQ.
         /// </summary>
         internal static string delete_combine {
             get {
@@ -205,7 +214,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAP.
+        ///   Looks up a localized string similar to AAR.
         /// </summary>
         internal static string emoji {
             get {
@@ -214,16 +223,34 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ABF.
+        ///   Looks up a localized string similar to AAS.
         /// </summary>
-        internal static string my_opencases {
+        internal static string my_packs {
             get {
-                return ResourceManager.GetString("my_opencases", resourceCulture);
+                return ResourceManager.GetString("my_packs", resourceCulture);
             }
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAQ.
+        ///   Looks up a localized string similar to ABE.
+        /// </summary>
+        internal static string open_pack {
+            get {
+                return ResourceManager.GetString("open_pack", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to AAT.
+        /// </summary>
+        internal static string open_random {
+            get {
+                return ResourceManager.GetString("open_random", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to AAU.
         /// </summary>
         internal static string price {
             get {
@@ -232,7 +259,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAR.
+        ///   Looks up a localized string similar to AAV.
         /// </summary>
         internal static string price_coins_from {
             get {
@@ -241,7 +268,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAS.
+        ///   Looks up a localized string similar to AAW.
         /// </summary>
         internal static string price_coins_to {
             get {
@@ -250,7 +277,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAT.
+        ///   Looks up a localized string similar to AAX.
         /// </summary>
         internal static string price_gems_from {
             get {
@@ -259,7 +286,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAU.
+        ///   Looks up a localized string similar to AAY.
         /// </summary>
         internal static string price_gems_to {
             get {
@@ -286,7 +313,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ABG.
+        ///   Looks up a localized string similar to AAX.
         /// </summary>
         internal static string send_private_sticker {
             get {
@@ -295,7 +322,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAX.
+        ///   Looks up a localized string similar to AAY.
         /// </summary>
         internal static string send_sticker {
             get {
@@ -304,7 +331,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to AAY.
+        ///   Looks up a localized string similar to AAZ.
         /// </summary>
         internal static string set {
             get {
@@ -322,16 +349,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Остановить.
-        /// </summary>
-        internal static string stop_bot {
-            get {
-                return ResourceManager.GetString("stop_bot", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ABB.
+        ///   Looks up a localized string similar to ABC.
         /// </summary>
         internal static string tier {
             get {
@@ -340,7 +358,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ABC.
+        ///   Looks up a localized string similar to ABD.
         /// </summary>
         internal static string unlimited_stickers {
             get {

+ 35 - 29
CardCollector/Resources/Command.resx

@@ -19,67 +19,67 @@
         <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
     </resheader>
     <data name="collect_income" xml:space="preserve">
-        <value>AAH</value>
+        <value>AAI</value>
     </data>
     <data name="author" xml:space="preserve">
         <value>AAA</value>
     </data>
     <data name="tier" xml:space="preserve">
-        <value>ABB</value>
+        <value>ABC</value>
     </data>
     <data name="emoji" xml:space="preserve">
-        <value>AAP</value>
+        <value>AAR</value>
     </data>
     <data name="sort" xml:space="preserve">
         <value>ABA</value>
     </data>
     <data name="cancel" xml:space="preserve">
-        <value>AAF</value>
+        <value>AAG</value>
     </data>
     <data name="set" xml:space="preserve">
-        <value>AAY</value>
+        <value>AAZ</value>
     </data>
     <data name="back" xml:space="preserve">
-        <value>AAB</value>
+        <value>AAC</value>
     </data>
     <data name="unlimited_stickers" xml:space="preserve">
-        <value>ABC</value>
+        <value>ABD</value>
     </data>
     <data name="send_sticker" xml:space="preserve">
-        <value>AAX</value>
+        <value>AAY</value>
     </data>
     <data name="select_sticker" xml:space="preserve">
         <value>AAV</value>
     </data>
     <data name="price_coins_from" xml:space="preserve">
-        <value>AAR</value>
+        <value>AAV</value>
     </data>
     <data name="price_coins_to" xml:space="preserve">
-        <value>AAS</value>
+        <value>AAW</value>
     </data>
     <data name="price_gems_from" xml:space="preserve">
-        <value>AAT</value>
+        <value>AAX</value>
     </data>
     <data name="price_gems_to" xml:space="preserve">
-        <value>AAU</value>
+        <value>AAY</value>
     </data>
     <data name="price" xml:space="preserve">
-        <value>AAQ</value>
+        <value>AAU</value>
     </data>
     <data name="buy_sticker" xml:space="preserve">
-        <value>AAE</value>
+        <value>AAF</value>
     </data>
     <data name="clear_chat" xml:space="preserve">
-        <value>AAG</value>
+        <value>AAH</value>
     </data>
     <data name="combine" xml:space="preserve">
-        <value>AAI</value>
+        <value>AAJ</value>
     </data>
     <data name="sell_on_auction" xml:space="preserve">
         <value>AAW</value>
     </data>
     <data name="count" xml:space="preserve">
-        <value>AAN</value>
+        <value>AAO</value>
     </data>
     <data name="confirm_buying" xml:space="preserve">
         <value>AAL</value>
@@ -88,30 +88,36 @@
         <value>AAM</value>
     </data>
     <data name="back_to_sticker" xml:space="preserve">
-        <value>AAD</value>
+        <value>AAE</value>
     </data>
     <data name="back_to_combine" xml:space="preserve">
-        <value>AAC</value>
+        <value>AAD</value>
     </data>
     <data name="delete_combine" xml:space="preserve">
-        <value>AAO</value>
+        <value>AAQ</value>
     </data>
     <data name="combine_stickers" xml:space="preserve">
-        <value>AAJ</value>
-    </data>
-    <data name="stop_bot" xml:space="preserve">
-        <value>Остановить</value>
+        <value>AAK</value>
     </data>
     <data name="control_panel" xml:space="preserve">
-        <value>ABD</value>
+        <value>AAN</value>
     </data>
-    <data name="my_opencases" xml:space="preserve">
-        <value>ABF</value>
+    <data name="my_packs" xml:space="preserve">
+        <value>AAS</value>
     </data>
     <data name="daily_tasks" xml:space="preserve">
-        <value>ABE</value>
+        <value>AAP</value>
     </data>
     <data name="send_private_sticker" xml:space="preserve">
-        <value>ABG</value>
+        <value>AAX</value>
+    </data>
+    <data name="open_random" xml:space="preserve">
+        <value>AAT</value>
+    </data>
+    <data name="author_menu" xml:space="preserve">
+        <value>AAB</value>
+    </data>
+    <data name="open_pack" xml:space="preserve">
+        <value>ABE</value>
     </data>
 </root>

+ 1 - 1
CardCollector/Resources/Constants.cs

@@ -27,6 +27,6 @@ namespace CardCollector.Resources
         
         /* Время оповещения и сброса ежедневных заданий */
         public static readonly TimeSpan DailyTaskAlert = DEBUG ? new TimeSpan(21, 0, 0) : new TimeSpan(12, 0, 0);
-        public static readonly TimeSpan DailyTaskReset = DEBUG ? new TimeSpan(21, 0, 0) : new TimeSpan(0, 0, 0);
+        public static readonly TimeSpan DailyTaskReset = DEBUG ? new TimeSpan(0, 13, 0) : new TimeSpan(0, 0, 0);
     }
 }

+ 7 - 2
CardCollector/Resources/Keyboard.cs

@@ -18,6 +18,12 @@ namespace CardCollector.Resources
             new KeyboardButton[] {Text.shop, Text.auction},
         }) {ResizeKeyboard = true};
 
+        public static readonly InlineKeyboardMarkup PackMenu = new(new[]
+        {
+            new[] {InlineKeyboardButton.WithCallbackData(Text.open_random, Command.open_random)},
+            new[] {InlineKeyboardButton.WithCallbackData(Text.open_author, Command.author_menu)}
+        });
+
         public static InlineKeyboardMarkup BackToFilters(string stickerTitle)
         {
             return new InlineKeyboardMarkup(new[]
@@ -60,7 +66,6 @@ namespace CardCollector.Resources
             new[] {InlineKeyboardButton.WithCallbackData("2", $"{Command.set}={Command.tier}=2")},
             new[] {InlineKeyboardButton.WithCallbackData("3", $"{Command.set}={Command.tier}=3")},
             new[] {InlineKeyboardButton.WithCallbackData("4", $"{Command.set}={Command.tier}=4")},
-            new[] {InlineKeyboardButton.WithCallbackData("5", $"{Command.set}={Command.tier}=5")},
             new[] {InlineKeyboardButton.WithCallbackData(Text.cancel, Command.back)},
         });
 
@@ -305,7 +310,7 @@ namespace CardCollector.Resources
             {
                 new[] {InlineKeyboardButton.WithCallbackData($"{Text.collect} {income}{Text.coin}", Command.collect_income)},
                 new[] {InlineKeyboardButton.WithCallbackData(Text.daily_tasks, Command.daily_tasks)},
-                new[] {InlineKeyboardButton.WithCallbackData(Text.my_opencases, Command.my_opencases)},
+                new[] {InlineKeyboardButton.WithCallbackData(Text.my_packs, Command.my_packs)},
             };
             if (privilegeLevel > 2) keyboard.Add(
                 new[] {InlineKeyboardButton.WithCallbackData(Text.control_panel, Command.control_panel)});

+ 73 - 1
CardCollector/Resources/Messages.Designer.cs

@@ -87,6 +87,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Пак художника.
+        /// </summary>
+        internal static string author_packs {
+            get {
+                return ResourceManager.GetString("author_packs", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Бот уходит на технический перерыв....
         /// </summary>
@@ -195,6 +204,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Внимание! На аукционе действует комиссия в размере 30%..
+        /// </summary>
+        internal static string comission_warning {
+            get {
+                return ResourceManager.GetString("comission_warning", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Подтвердите покупку:.
         /// </summary>
@@ -213,6 +231,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Поздравляем! Вы получили стикер:.
+        /// </summary>
+        internal static string congratulation {
+            get {
+                return ResourceManager.GetString("congratulation", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Текущие примененные фильтры:.
         /// </summary>
@@ -295,7 +322,7 @@ namespace CardCollector.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Введите вашу стоимость в алмазах.
+        ///   Looks up a localized string similar to Введите вашу стоимость в алмазах (за 1шт).
         /// </summary>
         internal static string enter_your_gems_price {
             get {
@@ -312,6 +339,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Наименьшая цена:.
+        /// </summary>
+        internal static string lower_price {
+            get {
+                return ResourceManager.GetString("lower_price", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Вы можете выбрать одну из опций ниже.
         /// </summary>
@@ -348,6 +384,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to У вас недостаточно паков.
+        /// </summary>
+        internal static string packs_count_zero {
+            get {
+                return ResourceManager.GetString("packs_count_zero", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Пожалуйста, введите только эмоцию.
         /// </summary>
@@ -375,6 +420,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Случайный пак.
+        /// </summary>
+        internal static string random_packs {
+            get {
+                return ResourceManager.GetString("random_packs", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Читаю документ....
         /// </summary>
@@ -500,5 +554,23 @@ namespace CardCollector.Resources {
                 return ResourceManager.GetString("your_cash", resourceCulture);
             }
         }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Ваши ежедневные задания:.
+        /// </summary>
+        internal static string your_daily_tasks {
+            get {
+                return ResourceManager.GetString("your_daily_tasks", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to У вас сейчас:.
+        /// </summary>
+        internal static string your_packs {
+            get {
+                return ResourceManager.GetString("your_packs", resourceCulture);
+            }
+        }
     }
 }

+ 25 - 1
CardCollector/Resources/Messages.resx

@@ -148,7 +148,7 @@
         <value>Введите вашу стоимость в монетах</value>
     </data>
     <data name="enter_your_gems_price" xml:space="preserve">
-        <value>Введите вашу стоимость в алмазах</value>
+        <value>Введите вашу стоимость в алмазах (за 1шт)</value>
     </data>
     <data name="confirm_selling" xml:space="preserve">
         <value>Подтвердите выставление</value>
@@ -165,4 +165,28 @@
     <data name="daily_task_alertation" xml:space="preserve">
         <value>Не забывайте заходить и выполнять ежедневные задания. Список ежедневных заданий вы можете посмотреть в профиле. Хорошего дня и приятного пользования нашим ботом!</value>
     </data>
+    <data name="your_daily_tasks" xml:space="preserve">
+        <value>Ваши ежедневные задания:</value>
+    </data>
+    <data name="your_packs" xml:space="preserve">
+        <value>У вас сейчас:</value>
+    </data>
+    <data name="random_packs" xml:space="preserve">
+        <value>Случайный пак</value>
+    </data>
+    <data name="author_packs" xml:space="preserve">
+        <value>Пак художника</value>
+    </data>
+    <data name="comission_warning" xml:space="preserve">
+        <value>Внимание! На аукционе действует комиссия в размере 30%.</value>
+    </data>
+    <data name="lower_price" xml:space="preserve">
+        <value>Наименьшая цена:</value>
+    </data>
+    <data name="congratulation" xml:space="preserve">
+        <value>Поздравляем! Вы получили стикер:</value>
+    </data>
+    <data name="packs_count_zero" xml:space="preserve">
+        <value>У вас недостаточно паков</value>
+    </data>
 </root>

+ 29 - 2
CardCollector/Resources/Text.Designer.cs

@@ -324,9 +324,9 @@ namespace CardCollector.Resources {
         /// <summary>
         ///   Looks up a localized string similar to Мои паки.
         /// </summary>
-        internal static string my_opencases {
+        internal static string my_packs {
             get {
-                return ResourceManager.GetString("my_opencases", resourceCulture);
+                return ResourceManager.GetString("my_packs", resourceCulture);
             }
         }
         
@@ -348,6 +348,24 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Открыть пак художника.
+        /// </summary>
+        internal static string open_author {
+            get {
+                return ResourceManager.GetString("open_author", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Открыть случайный пак.
+        /// </summary>
+        internal static string open_random {
+            get {
+                return ResourceManager.GetString("open_random", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to за.
         /// </summary>
@@ -501,6 +519,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Остановить.
+        /// </summary>
+        internal static string stop_bot {
+            get {
+                return ResourceManager.GetString("stop_bot", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Тир.
         /// </summary>

+ 10 - 1
CardCollector/Resources/Text.resx

@@ -177,7 +177,16 @@
     <data name="daily_tasks" xml:space="preserve">
         <value>Ежедневные задания</value>
     </data>
-    <data name="my_opencases" xml:space="preserve">
+    <data name="my_packs" xml:space="preserve">
         <value>Мои паки</value>
     </data>
+    <data name="open_random" xml:space="preserve">
+        <value>Открыть случайный пак</value>
+    </data>
+    <data name="open_author" xml:space="preserve">
+        <value>Открыть пак художника</value>
+    </data>
+    <data name="stop_bot" xml:space="preserve">
+        <value>Остановить</value>
+    </data>
 </root>