using AscNet.Common.Database; using AscNet.Common.MsgPack; using AscNet.Common.Util; using AscNet.GameServer.Handlers; using AscNet.Logging; using AscNet.Table.V2.client.draw; using AscNet.Table.V2.share.character; using AscNet.Table.V2.share.character.quality; using AscNet.Table.V2.share.equip; using AscNet.Table.V2.share.item; using System; namespace AscNet.GameServer.Game { internal class DrawManager { public static readonly List drawSceneTables = TableReaderV2.Parse(); public static readonly List charactersTables = TableReaderV2.Parse(); public static readonly List characterQualitiesTables = TableReaderV2.Parse(); static readonly Logger log = new(typeof(DrawManager), LogLevel.DEBUG, LogLevel.DEBUG); #region DrawTags public const int TagBase = 1; public const int TagEvent = 2; public const int TagSpecialEvent = 3; public const int TagTargetUniframe = 4; public const int TagCollab = 5; public const int TagEndlessSummerBlue = 6; public const int TagCUB = 7; #endregion #region Groups public const int GroupMemberTarget = 1; public const int GroupWeaponResearch = 2; public const int GroupTargetWeaponResearch = 4; public const int GroupDormitoryResearch = 6; public const int GroupThemedTargetWeapon = 10; public const int GroupThemedEventConstruct = 11; public const int GroupArrivalConstruct = 12; public const int GroupFateArrivalConstruct = 13; public const int GroupArrivalEventConstruct = 14; public const int GroupFateThemedConstruct = 15; public const int GroupTargetUniframe = 16; public const int GroupAnniversary = 17; public const int GroupFateAnniversaryLimited = 18; public const int GroupCollabTarget = 19; public const int GroupFateCollabTarget = 20; public const int GroupCollabWeaponTarget = 21; public const int GroupCUBTarget = 22; public const int GroupWishingTarget = 23; public const int GroupFateWishingTarget = 24; #endregion private readonly Dictionary selectedDrawUp = new(); public void SetUpDrawByGroupId(int groupId, int drawId) { if (selectedDrawUp.ContainsKey(groupId)) selectedDrawUp[groupId] = drawId; else selectedDrawUp.Add(groupId, drawId); } public static List GetDrawInfosByGroup(int groupId) { List infos = new(); switch (groupId) { case GroupArrivalConstruct: // Querying every character scene that is omniframe. infos.AddRange(drawSceneTables.Where(x => x.Type == 1 && charactersTables.Any(y => { // only get the S chars since this is Arrival Construct int firstQuality = characterQualitiesTables.Where(x => x.CharacterId == y.Id).OrderBy(x => x.Quality).FirstOrDefault()?.Quality ?? 0; return y.Type == 1 && y.Id == x.ModelId && firstQuality == 3; })).DistinctBy(x => x.ModelId).Select(x => new DrawInfo() { Id = x.Id, UseItemId = Inventory.FreeGem, UseItemCount = 1, GroupId = GroupArrivalConstruct, BtnDrawCount = { 1, 10 }, Banner = "Assets/Product/Ui/Scene3DPrefab/UiMain3dXiahuo.prefab", EndTime = DateTimeOffset.Now.ToUnixTimeSeconds() * 2 })); break; case GroupMemberTarget: // Querying every character scene that is omniframe. infos.AddRange(drawSceneTables.Where(x => x.Type == 1 && charactersTables.Any(y => { // only get the A chars since this is member target int firstQuality = characterQualitiesTables.Where(x => x.CharacterId == y.Id).OrderBy(x => x.Quality).FirstOrDefault()?.Quality ?? 0; return y.Type == 1 && y.Id == x.ModelId && firstQuality == 2; })).DistinctBy(x => x.ModelId).Select(x => new DrawInfo() { Id = x.Id, UseItemId = Inventory.FreeGem, UseItemCount = 1, GroupId = GroupMemberTarget, BtnDrawCount = { 1, 10 }, Banner = "Assets/Product/Ui/Scene3DPrefab/UiMain3dXiahuo.prefab", EndTime = DateTimeOffset.Now.ToUnixTimeSeconds() * 2 })); break; } return infos; } public static int GetGroupByDrawId(int draw) { foreach (var groupId in new int[] { GroupMemberTarget, GroupWeaponResearch, GroupTargetWeaponResearch, GroupDormitoryResearch, GroupThemedTargetWeapon, GroupThemedEventConstruct, GroupArrivalConstruct, GroupFateArrivalConstruct, GroupArrivalEventConstruct, GroupFateThemedConstruct, GroupTargetUniframe, GroupAnniversary, GroupFateAnniversaryLimited, GroupCollabTarget, GroupFateCollabTarget, GroupCollabWeaponTarget, GroupCUBTarget, GroupWishingTarget, GroupFateWishingTarget}) { if (GetDrawInfosByGroup(groupId).Any(x => x.Id == draw)) { return groupId; } } log.Error($"Get group not found for draw {draw}"); return 0; } public static List DrawDraw(int drawId) { List rewards = new(); var drawScene = drawSceneTables.Find(x => x.Id == drawId); var drawPool = TableReaderV2.Parse().Find(x => x.Id == drawId); if (drawScene is null || drawPool is null) { log.Error($"Invalid draw id {drawId}"); return rewards; } float random = Random.Shared.NextSingle(); switch (drawScene.Type) { case 1: // Character if (random >= 0.98f) { // S Character float rate = Random.Shared.NextSingle(); re_rate: if (rate <= 0.3f) { // Rate off List pool = new(); foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality >= 3 && drawPool.GoodsId.Contains(character.Id)) { pool.Add(charId); } } if (pool.Count < 1) { foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality >= 3 && !drawPool.UpGoodsId.Contains(character.Id)) { pool.Add(charId); } } } if (pool.Count > 0) { int rand = pool[Random.Shared.Next(pool.Count)]; CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == rand); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == rand); rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, Count = 1, TemplateId = rand }); } } else { if (drawPool.UpGoodsId.Count == 1) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == drawPool.UpGoodsId[0]); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == drawPool.UpGoodsId[0]); rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, Count = 1, TemplateId = drawPool.UpGoodsId[0] }); } else if (drawPool.UpGoodsId.Count > 0) { int rand = drawPool.UpGoodsId[Random.Shared.Next(drawPool.UpGoodsId.Count)]; CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == rand); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == rand); rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, Count = 1, TemplateId = rand }); } else { rate = 0f; goto re_rate; } } } else if (random >= 0.9f) { // A Character float rate = Random.Shared.NextSingle(); re_rate: if (rate >= 0.19f) { // Rate on if (drawPool.UpGoodsId.Count == 1) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == drawPool.UpGoodsId[0]); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == drawPool.UpGoodsId[0]); if (characterQuality?.Quality == 2) rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, Count = 1, TemplateId = drawPool.UpGoodsId[0] }); } if (rewards.Count < 1) { rate = 0; goto re_rate; } } else { List pool = new(); foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality == 2 && drawPool.GoodsId.Contains(character.Id)) { pool.Add(charId); } } if (pool.Count < 1) { foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality == 2 && !drawPool.UpGoodsId.Contains(character.Id)) { pool.Add(charId); } } } if (pool.Count > 0) { int rand = pool[Random.Shared.Next(pool.Count)]; CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == rand); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == rand); rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, Count = 1, TemplateId = rand }); } } } else if (random >= 0.82f) { List pool = new(); foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality == 1 && drawPool.GoodsId.Contains(character.Id)) { pool.Add(charId); } } if (pool.Count < 1) { foreach (var charId in TableReaderV2.Parse().Select(x => x.Id)) { CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == charId); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == charId); if (character is null || characterQuality is null) continue; if (characterQuality.Quality == 1 && !drawPool.UpGoodsId.Contains(character.Id)) { pool.Add(charId); } } } if (pool.Count > 0) { int rand = pool[Random.Shared.Next(pool.Count)]; CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == rand); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == rand); rewards.Add(new() { RewardType = (int)RewardType.Character, Quality = characterQuality?.Quality ?? 0, TemplateId = rand }); } } else if (random >= 0.61f) { // Shard var pool = new List(); pool.AddRange(drawPool.GoodsId); pool.AddRange(drawPool.UpGoodsId); if (pool.Count > 0) { int rand = pool[Random.Shared.Next(pool.Count)]; CharacterTable? character = TableReaderV2.Parse().Find(x => x.Id == rand); CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == rand); if (character is not null) rewards.Add(new() { RewardType = (int)RewardType.Item, Count = characterQuality?.Quality >= 3 ? 3 : (characterQuality?.Quality == 2 ? 8 : 12), Quality = characterQuality?.Quality ?? 0, TemplateId = character.ItemId }); } } else if (random >= 0.39f) { // 4* Equip var pool = TableReaderV2.Parse().Where(x => x.Quality == 4).ToList(); if (pool.Count > 0) { EquipTable rand = pool[Random.Shared.Next(pool.Count)]; rewards.Add(new() { RewardType = (int)RewardType.Equip, Count = 1, Quality = rand.Quality, TemplateId = rand.Id }); } } else if (random >= 0.25f) { // Overclock mats var pool = TableReaderV2.Parse().Where(x => x.Id >= 40100 && x.Id < 40200).ToList(); if (pool.Count > 0) { ItemTable rand = pool[Random.Shared.Next(pool.Count)]; rewards.Add(new() { RewardType = (int)RewardType.Item, Count = rand.Quality > 3 ? 1 : 3, Quality = rand.Quality, TemplateId = rand.Id }); } } else if (random >= 0.18f) { // Exp mats var pool = TableReaderV2.Parse().Where(x => x.Id >= 30011 && x.Id < 30015).ToList(); if (pool.Count > 0) { ItemTable rand = pool[Random.Shared.Next(pool.Count)]; rewards.Add(new() { RewardType = (int)RewardType.Item, Count = rand.Quality > 3 ? 1 : 3, Quality = rand.Quality, TemplateId = rand.Id }); } } else { // Cog boxes var pool = TableReaderV2.Parse().Where(x => x.Name.StartsWith("Cog Pack")).ToList(); if (pool.Count > 0) { ItemTable rand = pool[Random.Shared.Next(pool.Count)]; rewards.Add(new() { RewardType = (int)RewardType.Item, Count = 1, Quality = rand.Quality, TemplateId = rand.Id }); } } break; case 2: // Weapon break; case 3: // CUB break; default: break; } return rewards; } } }