OSDN Git Service

無条件先制対潜可能艦にFletcherとJanus改を加える
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Model / QuestInfo.cs
index 0f2d36f..575c84a 100644 (file)
@@ -19,7 +19,6 @@ using System.Linq;
 using System.Windows.Forms;\r
 using System.Xml.Serialization;\r
 using KancolleSniffer.Util;\r
-using static System.Math;\r
 \r
 namespace KancolleSniffer.Model\r
 {\r
@@ -47,6 +46,13 @@ namespace KancolleSniffer.Model
                       new[] {"燃", "弾", "鋼", "ボ", "建造", "修復", "開発", "改修"}\r
                           .Zip(Material, (m, num) => num == 0 ? "" : m + num)\r
                           .Where(s => !string.IsNullOrEmpty(s))));\r
+\r
+        public QuestStatus Clone()\r
+        {\r
+            var clone = (QuestStatus)MemberwiseClone();\r
+            clone.Count = Count.Clone();\r
+            return clone;\r
+        }\r
     }\r
 \r
     public enum QuestInterval\r
@@ -59,206 +65,12 @@ namespace KancolleSniffer.Model
         Quarterly\r
     }\r
 \r
-    public class QuestSpec\r
-    {\r
-        public QuestInterval Interval { get; set; }\r
-        public int Max { get; set; }\r
-        public int[] MaxArray { get; set; }\r
-        public bool AdjustCount { get; set; } = true;\r
-        public int Shift { get; set; }\r
-        public int[] Material { get; set; }\r
-    }\r
-\r
-    public class QuestSortie : QuestSpec\r
-    {\r
-        public string Rank { get; set; }\r
-        public int[] Maps { get; set; }\r
-\r
-        public static int CompareRank(string a, string b)\r
-        {\r
-            const string ranks = "SABCDE";\r
-            return ranks.IndexOf(a, StringComparison.Ordinal) -\r
-                   ranks.IndexOf(b, StringComparison.Ordinal);\r
-        }\r
-\r
-        public bool Check(string rank, int map, bool boss)\r
-        {\r
-            return (Rank == null || CompareRank(rank, Rank) <= 0) &&\r
-                   (Maps == null || Maps.Contains(map) && boss);\r
-        }\r
-    }\r
-\r
-    public class QuestEnemyType : QuestSpec\r
-    {\r
-        public int[] EnemyType { get; set; } = new int[0];\r
-\r
-        public int CountResult(IEnumerable<ShipStatus> enemyResult) =>\r
-            enemyResult.Count(ship => ship.NowHp == 0 && EnemyType.Contains(ship.Spec.ShipType));\r
-    }\r
-\r
-    public class QuestPractice : QuestSpec\r
-    {\r
-        public bool Win { get; set; }\r
-        public bool Check(string rank) => !Win || QuestSortie.CompareRank(rank, "B") <= 0;\r
-    }\r
-\r
-    public class QuestMission : QuestSpec\r
-    {\r
-        public int[] Ids { get; set; }\r
-        public bool Check(int id) => Ids == null || Ids.Contains(id);\r
-    }\r
-\r
-    public class QuestDestroyItem : QuestSpec\r
-    {\r
-        public int[] Types { get; set; }\r
-        public int[] Ids { get; set; }\r
-\r
-        public bool Count(QuestCount count, ItemSpec[] specs)\r
-        {\r
-            if (count.NowArray == null)\r
-            {\r
-                var num = specs.Count(spec => Types?.Contains(spec.Type) ?? (Ids?.Contains(spec.Id) ?? true));\r
-                count.Now += num;\r
-                return num > 0;\r
-            }\r
-            if (Types == null && Ids == null)\r
-                return false;\r
-            var result = false;\r
-            for (var i = 0; i < count.NowArray.Length; i++)\r
-            {\r
-                var num = specs.Count(spec => Types != null ? Types[i] == spec.Type : Ids[i] == spec.Id);\r
-                count.NowArray[i] += num;\r
-                if (num > 0)\r
-                    result = true;\r
-            }\r
-            return result;\r
-        }\r
-    }\r
-\r
-    public class QuestPowerUp : QuestSpec\r
-    {\r
-    }\r
-\r
-    public class QuestCount\r
-    {\r
-        public int Id { get; set; }\r
-        public int Now { get; set; }\r
-        public int[] NowArray { get; set; }\r
-\r
-        [XmlIgnore]\r
-        public QuestSpec Spec { get; set; }\r
-\r
-        public bool AdjustCount(int progress)\r
-        {\r
-            if (!Spec.AdjustCount)\r
-                return false;\r
-            if (NowArray != null)\r
-            {\r
-                if (progress != 100)\r
-                    return false;\r
-                NowArray = NowArray.Zip(Spec.MaxArray, Max).ToArray();\r
-                return true;\r
-            }\r
-            var next = 0;\r
-            switch (progress)\r
-            {\r
-                case 0:\r
-                    next = 50;\r
-                    break;\r
-                case 50:\r
-                    next = 80;\r
-                    break;\r
-                case 80:\r
-                    next = 100;\r
-                    break;\r
-                case 100:\r
-                    next = 100000;\r
-                    break;\r
-            }\r
-            var now = Now + Spec.Shift;\r
-            var max = Spec.Max + Spec.Shift;\r
-            var low = (int)Ceiling(max * progress / 100.0);\r
-            if (low >= max && progress != 100)\r
-                low = max - 1;\r
-            var high = (int)Ceiling(max * next / 100.0);\r
-            if (now < low)\r
-            {\r
-                Now = low - Spec.Shift;\r
-                return true;\r
-            }\r
-            if (now >= high)\r
-            {\r
-                Now = high - 1 - Spec.Shift;\r
-                return true;\r
-            }\r
-            return false;\r
-        }\r
-\r
-        public override string ToString()\r
-        {\r
-            if (Id == 280 || Id == 426 || Id == 854 || Id == 873 || Id == 888 || Id == 894)\r
-                return $"{NowArray.Count(n => n >= 1)}/{Spec.MaxArray.Length}";\r
-            return NowArray != null\r
-                ? string.Join(" ", NowArray.Zip(Spec.MaxArray, (n, m) => $"{n}/{m}"))\r
-                : $"{Now}/{Spec.Max}";\r
-        }\r
-\r
-        public string ToToolTip()\r
-        {\r
-            switch (Id)\r
-            {\r
-                case 280:\r
-                    return string.Join(" ",\r
-                        new[] {"1-2", "1-3", "1-4", "2-1"}.Zip(NowArray, (map, n) => n >= 1 ? map : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 426:\r
-                    return string.Join(" ",\r
-                        new[] {"警備任務", "対潜警戒任務", "海上護衛任務", "強硬偵察任務"}\r
-                            .Zip(NowArray, (mission, n) => n >= 1 ? mission : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 428:\r
-                    return string.Join(" ",\r
-                        new[] {"対潜警戒任務", "海峡警備行動", "長時間対潜警戒"}.Zip(NowArray, (mission, n) => n >= 1 ? mission + n : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 854:\r
-                    return string.Join(" ",\r
-                        new[] {"2-4", "6-1", "6-3", "6-4"}.Zip(NowArray, (map, n) => n >= 1 ? map : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 873:\r
-                    return string.Join(" ",\r
-                        new[] {"3-1", "3-2", "3-3"}.Zip(NowArray, (map, n) => n >= 1 ? map : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 888:\r
-                    return string.Join(" ",\r
-                        new[] {"5-1", "5-3", "5-4"}.Zip(NowArray, (map, n) => n >= 1 ? map : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 688:\r
-                    return string.Join(" ",\r
-                        new[] {"艦戦", "艦爆", "艦攻", "水偵"}.Zip(NowArray, (type, n) => n >= 1 ? type + n : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 893:\r
-                    return string.Join(" ",\r
-                        new[] {"1-5", "7-1", "7-2G", "7-2M"}.Zip(NowArray, (map, n) => n >= 1 ? $"{map}:{n}" : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-                case 894:\r
-                    return string.Join(" ",\r
-                        new[] {"1-3", "1-4", "2-1", "2-2", "2-3"}.Zip(NowArray, (map, n) => n >= 1 ? map : "")\r
-                            .Where(s => !string.IsNullOrEmpty(s)));\r
-            }\r
-            return "";\r
-        }\r
-\r
-        public bool Cleared => NowArray?.Zip(Spec.MaxArray, (n, m) => n >= m).All(x => x) ??\r
-                               Spec.Max != 0 && Now >= Spec.Max;\r
-    }\r
-\r
     public class QuestInfo : IHaveState\r
     {\r
         private readonly SortedDictionary<int, QuestStatus> _quests = new SortedDictionary<int, QuestStatus>();\r
         private readonly QuestCountList _countList = new QuestCountList();\r
-        private readonly ItemInfo _itemInfo;\r
-        private readonly BattleInfo _battleInfo;\r
         private readonly Func<DateTime> _nowFunc = () => DateTime.Now;\r
+        private DateTime _now;\r
         private DateTime _lastReset;\r
         private IEnumerable<QuestStatus> _clearedQuest = new List<QuestStatus>();\r
 \r
@@ -271,12 +83,12 @@ namespace KancolleSniffer.Model
 \r
         public int AcceptMax { get; set; } = 5;\r
 \r
+        public SortedDictionary<int, QuestStatus> QuestDictionary => _quests;\r
+\r
         public QuestStatus[] Quests => _quests.Values.ToArray();\r
 \r
-        public QuestInfo(ItemInfo itemInfo, BattleInfo battleInfo, Func<DateTime> nowFunc = null)\r
+        public QuestInfo(Func<DateTime> nowFunc = null)\r
         {\r
-            _itemInfo = itemInfo;\r
-            _battleInfo = battleInfo;\r
             if (nowFunc != null)\r
                 _nowFunc = nowFunc;\r
         }\r
@@ -342,30 +154,34 @@ namespace KancolleSniffer.Model
                             quest.Progress = 100;\r
                             goto case 2;\r
                         case 2:\r
-                            AddQuest(quest, true);\r
+                            SetProcessedQuest(quest);\r
                             break;\r
                     }\r
                 }\r
                 if (_quests.Count <= AcceptMax)\r
                     break;\r
                 /*\r
-                 * ほかのPCで任務を達成した場合、任務が消えずに受領した任務の数が_questCountを超えることがある。\r
+                 * ほかのPCで任務を達成した場合、任務が消えずに受領した任務の数がAcceptMaxを超えることがある。\r
                  * その場合はいったん任務をクリアして、現在のページの任務だけを登録し直す。\r
                  */\r
                 _quests.Clear();\r
             }\r
         }\r
 \r
-        private void AddQuest(QuestStatus quest, bool adjustCount)\r
+        private void SetProcessedQuest(QuestStatus quest)\r
         {\r
             var count = _countList.GetCount(quest.Id);\r
-            if (adjustCount)\r
-            {\r
-                if (count.AdjustCount(quest.Progress))\r
-                    NeedSave = true;\r
-                quest.Material = quest.Material.Concat(count.Spec.Material).ToArray();\r
-            }\r
-            quest.Count = count;\r
+            if (count.AdjustCount(quest.Progress))\r
+                NeedSave = true;\r
+            quest.Material = quest.Material.Concat(count.Spec.Material).ToArray();\r
+            if (!_quests.ContainsKey(quest.Id))\r
+                NeedSave = true;\r
+            SetQuest(quest);\r
+        }\r
+\r
+        private void SetQuest(QuestStatus quest)\r
+        {\r
+            quest.Count = _countList.GetCount(quest.Id);\r
             quest.Color = quest.Category <= _color.Length ? _color[quest.Category - 1] : Control.DefaultBackColor;\r
             _quests[quest.Id] = quest;\r
         }\r
@@ -377,523 +193,64 @@ namespace KancolleSniffer.Model
 \r
         private void ResetQuests()\r
         {\r
-            var now = _nowFunc();\r
-            var daily = now.Date.AddHours(5);\r
-            if (now.Hour < 5)\r
-                daily = daily.AddDays(-1);\r
-            if (!(_lastReset < daily && daily <= now))\r
+            _now = _nowFunc();\r
+            if (!CrossBoundary(LastMorning))\r
                 return;\r
             RemoveQuest(QuestInterval.Daily);\r
             _countList.Remove(QuestInterval.Daily);\r
-            var weekly = now.Date.AddDays(-((6 + (int)now.DayOfWeek) % 7)).AddHours(5);\r
-            if (_lastReset < weekly && weekly <= now)\r
-            {\r
-                RemoveQuest(QuestInterval.Weekly);\r
-                _countList.Remove(QuestInterval.Weekly);\r
-            }\r
-            var monthly = new DateTime(now.Year, now.Month, 1, 5, 0, 0);\r
-            if (_lastReset < monthly && monthly <= now)\r
-            {\r
-                RemoveQuest(QuestInterval.Monthly);\r
-                _countList.Remove(QuestInterval.Monthly);\r
-            }\r
-            var season = now.Month / 3;\r
-            var quarterly = new DateTime(now.Year - (season == 0 ? 1 : 0), (season == 0 ? 12 : season * 3), 1, 5, 0, 0);\r
-            if (_lastReset < quarterly && quarterly <= now)\r
-            {\r
-                RemoveQuest(QuestInterval.Quarterly);\r
-                _countList.Remove(QuestInterval.Quarterly);\r
-            }\r
-            _lastReset = now;\r
+            ResetWeekly();\r
+            ResetMonthly();\r
+            ResetQuarterly();\r
+            _lastReset = _now;\r
             NeedSave = true;\r
         }\r
 \r
-        private void RemoveQuest(QuestInterval interval)\r
-        {\r
-            foreach (var id in\r
-                (from kv in _quests\r
-                    where kv.Value.Count.Spec.Interval == interval || // 輸送5と空母3はカウンタを見ないとデイリーにならない\r
-                          kv.Value.Interval == interval\r
-                    select kv.Key).ToArray())\r
-                _quests.Remove(id);\r
-        }\r
-\r
-        private int _map;\r
-        private int _cell;\r
-        private bool _boss;\r
-\r
-        public void InspectMapStart(dynamic json)\r
-        {\r
-            if (_quests.TryGetValue(214, out var ago)) // あ号\r
-                ago.Count.NowArray[0]++;\r
-            InspectMapNext(json);\r
-        }\r
-\r
-        public void InspectMapNext(dynamic json)\r
-        {\r
-            _map = (int)json.api_maparea_id * 10 + (int)json.api_mapinfo_no;\r
-            _cell = json.api_no() ? (int)json.api_no : 0;\r
-            _boss = (int)json.api_event_id == 5;\r
-\r
-            if (_quests.TryGetValue(861, out var q861))\r
-            {\r
-                if (_map == 16 && (int)json.api_event_id == 8)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.ShipType)\r
-                        .ToArray();\r
-                    if (fleet.Count(s => s == 10 || s == 22) == 2)\r
-                        IncrementCount(q861.Count);\r
-                }\r
-            }\r
-        }\r
-\r
-        public void InspectBattleResult(dynamic json)\r
-        {\r
-            var rank = json.api_win_rank;\r
-            foreach (var quest in _quests.Values)\r
-            {\r
-                var count = quest.Count;\r
-                switch (count.Spec)\r
-                {\r
-                    case QuestSortie sortie:\r
-                        if (count.Id == 216 && !_boss || sortie.Check(rank, _map, _boss))\r
-                            IncrementCount(count);\r
-                        break;\r
-                    case QuestEnemyType enemyType:\r
-                        var num = enemyType.CountResult(\r
-                            _battleInfo.Result.Enemy.Main.Concat(_battleInfo.Result.Enemy.Guard));\r
-                        if (num > 0)\r
-                            AddCount(count, num);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(214, out var ago))\r
-            {\r
-                var count = ago.Count;\r
-                if (_boss)\r
-                {\r
-                    IncrementNowArray(count, 2);\r
-                    if (QuestSortie.CompareRank(rank, "B") <= 0)\r
-                        IncrementNowArray(count, 3);\r
-                }\r
-                if (rank == "S")\r
-                    IncrementNowArray(count, 1);\r
-            }\r
-            if (_quests.TryGetValue(249, out var q249))\r
-            {\r
-                if (_map == 25 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.Id)\r
-                        .ToArray();\r
-                    if (fleet.Intersect(new[] {62, 63, 64, 265, 266, 268, 319, 192, 194}).Count() == 3)\r
-                        IncrementCount(q249.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(257, out var q257))\r
-            {\r
-                if (_map == 14 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.ShipType)\r
-                        .ToArray();\r
-                    if (fleet[0] == 3 && fleet.Count(s => s == 3) <= 3 && fleet.All(s => s == 2 || s == 3))\r
-                        IncrementCount(q257.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(259, out var q259))\r
-            {\r
-                if (_map == 51 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec).ToArray();\r
-                    // ReSharper disable once IdentifierTypo\r
-                    var ctype = new[]\r
-                    {\r
-                        2, // 伊勢型\r
-                        19, // 長門型\r
-                        26, // 扶桑型\r
-                        37 // 大和型\r
-                    };\r
-                    if (fleet.Select(s => s.ShipClass).Count(c => ctype.Contains(c)) == 3 &&\r
-                        fleet.Count(s => s.ShipType == 3) > 0)\r
-                    {\r
-                        IncrementCount(q259.Count);\r
-                    }\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(264, out var q264))\r
-            {\r
-                if (_map == 42 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec)\r
-                        .ToArray();\r
-                    if (fleet.Count(spec => spec.ShipType == 2) >= 2 &&\r
-                        fleet.Count(spec => spec.IsAircraftCarrier) >= 2)\r
-                        IncrementCount(q264.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(266, out var q266))\r
-            {\r
-                if (_map == 25 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.ShipType)\r
-                        .ToArray();\r
-                    if (fleet[0] == 2 && fleet.OrderBy(x => x).SequenceEqual(new[] {2, 2, 2, 2, 3, 5}))\r
-                        IncrementCount(q266.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(280, out var q280))\r
-            {\r
-                if (!(_boss && QuestSortie.CompareRank(rank, "S") == 0))\r
-                    return;\r
-                var shipTypes = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.ShipType)\r
-                    .ToArray();\r
-                if (!(shipTypes.Count(type => type == 1 || type == 2) >= 3 &&\r
-                      shipTypes.Any(type => new[] {3, 4, 7, 21}.Contains(type))))\r
-                    return;\r
-                var count = q280.Count;\r
-                switch (_map)\r
-                {\r
-                    case 12:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 13:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 14:\r
-                        IncrementNowArray(count, 2);\r
-                        break;\r
-                    case 21:\r
-                        IncrementNowArray(count, 3);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(854, out var opz) && _boss)\r
-            {\r
-                var count = opz.Count;\r
-                switch (_map)\r
-                {\r
-                    case 24 when QuestSortie.CompareRank(rank, "A") <= 0:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 61 when QuestSortie.CompareRank(rank, "A") <= 0:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 63 when QuestSortie.CompareRank(rank, "A") <= 0:\r
-                        IncrementNowArray(count, 2);\r
-                        NeedSave = true;\r
-                        break;\r
-                    case 64 when QuestSortie.CompareRank(rank, "S") <= 0:\r
-                        IncrementNowArray(count, 3);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(862, out var q862))\r
-            {\r
-                if (_map == 63 && _boss && QuestSortie.CompareRank(rank, "A") <= 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.ShipType)\r
-                        .ToArray();\r
-                    if (fleet.Count(s => s == 3) >= 2 && fleet.Count(s => s == 16) >= 1)\r
-                        IncrementCount(q862.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(873, out var q873))\r
-            {\r
-                if (_battleInfo.Result.Friend.Main.Count(s => s.NowHp > 0 && s.Spec.ShipType == 3) >= 1 &&\r
-                    _boss && QuestSortie.CompareRank(rank, "A") <= 0)\r
-                {\r
-                    var count = q873.Count;\r
-                    switch (_map)\r
-                    {\r
-                        case 31:\r
-                            IncrementNowArray(count, 0);\r
-                            break;\r
-                        case 32:\r
-                            IncrementNowArray(count, 1);\r
-                            break;\r
-                        case 33:\r
-                            IncrementNowArray(count, 2);\r
-                            break;\r
-                    }\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(875, out var q875))\r
-            {\r
-                if (_map == 54 && _boss && QuestSortie.CompareRank(rank, "S") == 0)\r
-                {\r
-                    var fleet = _battleInfo.Result.Friend.Main.Where(s => s.NowHp > 0).Select(s => s.Spec.Id).ToArray();\r
-                    if (fleet.Contains(543) && fleet.Intersect(new[] {344, 345, 359}).Any())\r
-                        IncrementCount(q875.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(888, out var q888))\r
-            {\r
-                if (!_boss || QuestSortie.CompareRank(rank, "S") != 0)\r
-                    return;\r
-                var fleet = from ship in _battleInfo.Result.Friend.Main where ship.NowHp > 0 select ship.Spec.Id;\r
-                var member = new[]\r
-                {\r
-                    69, 272, 427, // 鳥海\r
-                    61, 264, // 青葉\r
-                    123, 295, 142, // 衣笠\r
-                    59, 262, 416, // 古鷹\r
-                    60, 263, 417, // 加古\r
-                    51, 213, 477, // 天龍\r
-                    115, 293 // 夕張\r
-                };\r
-                if (fleet.Intersect(member).Count() < 4)\r
-                    return;\r
-                var count = q888.Count;\r
-                switch (_map)\r
-                {\r
-                    case 51:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 53:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 54:\r
-                        IncrementNowArray(count, 2);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(893, out var q893))\r
-            {\r
-                if (!_boss || QuestSortie.CompareRank(rank, "S") != 0)\r
-                    return;\r
-                var count = q893.Count;\r
-                switch (_map)\r
-                {\r
-                    case 15:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 71:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 72:\r
-                        if (_cell == 7)\r
-                        {\r
-                            IncrementNowArray(count, 2);\r
-                            break;\r
-                        }\r
-                        IncrementNowArray(count, 3);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(894, out var q894))\r
-            {\r
-                if (!_boss ||\r
-                    QuestSortie.CompareRank(rank, "S") != 0 ||\r
-                    !_battleInfo.Result.Friend.Main.Any(s => s.Spec.IsAircraftCarrier && s.NowHp > 0))\r
-                    return;\r
-                var count = q894.Count;\r
-                switch (_map)\r
-                {\r
-                    case 13:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 14:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 21:\r
-                        IncrementNowArray(count, 2);\r
-                        break;\r
-                    case 22:\r
-                        IncrementNowArray(count, 3);\r
-                        break;\r
-                    case 23:\r
-                        IncrementNowArray(count, 4);\r
-                        break;\r
-                }\r
-            }\r
-        }\r
-\r
-        private int _questFleet;\r
-\r
-        public void StartPractice(string request)\r
-        {\r
-            var values = HttpUtility.ParseQueryString(request);\r
-            _questFleet = int.Parse(values["api_deck_id"]) - 1;\r
-        }\r
-\r
-        public void InspectPracticeResult(dynamic json)\r
-        {\r
-            foreach (var quest in _quests.Values)\r
-            {\r
-                var count = quest.Count;\r
-                if (!(count.Spec is QuestPractice practice))\r
-                    continue;\r
-                if (practice.Check(json.api_win_rank))\r
-                    IncrementCount(count);\r
-            }\r
-            if (_quests.TryGetValue(318, out var q318))\r
-            {\r
-                if (_questFleet == 0 && QuestSortie.CompareRank(json.api_win_rank, "B") <= 0 &&\r
-                    _battleInfo.Result.Friend.Main.Count(s => s.Spec.ShipType == 3) >= 2)\r
-                {\r
-                    IncrementCount(q318.Count);\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(330, out var q330))\r
-            {\r
-                var fleet = _battleInfo.Result.Friend.Main;\r
-                if (QuestSortie.CompareRank(json.api_win_rank, "B") <= 0 &&\r
-                    fleet.Count(s => s.Spec.IsAircraftCarrier) >= 2 &&\r
-                    fleet.Count(s => s.Spec.ShipType == 2) >= 2 &&\r
-                    fleet[0].Spec.IsAircraftCarrier)\r
-                {\r
-                    IncrementCount(q330.Count);\r
-                }\r
-            }\r
-        }\r
-\r
-        private readonly int[] _missionId = new int[ShipInfo.FleetCount];\r
-\r
-        public void InspectDeck(dynamic json)\r
-        {\r
-            foreach (var entry in json)\r
-                _missionId[(int)entry.api_id - 1] = (int)entry.api_mission[1];\r
-        }\r
+        private DateTime LastMorning => _now.Date.AddDays(_now.Hour < 5 ? -1 : 0).AddHours(5);\r
 \r
-        public void InspectMissionResult(string request, dynamic json)\r
+        private void ResetWeekly()\r
         {\r
-            var values = HttpUtility.ParseQueryString(request);\r
-            var deck = int.Parse(values["api_deck_id"]);\r
-            if ((int)json.api_clear_result == 0)\r
+            if (!CrossBoundary(LastMonday.AddHours(5)))\r
                 return;\r
-            var mid = _missionId[deck - 1];\r
-            foreach (var quest in _quests.Values)\r
-            {\r
-                var count = quest.Count;\r
-                if (!(count.Spec is QuestMission mission))\r
-                    continue;\r
-                if (mission.Check(mid))\r
-                    IncrementCount(count);\r
-            }\r
-            if (_quests.TryGetValue(426, out var q426))\r
-            {\r
-                var count = q426.Count;\r
-                switch (mid)\r
-                {\r
-                    case 3:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 4:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 5:\r
-                        IncrementNowArray(count, 2);\r
-                        break;\r
-                    case 10:\r
-                        IncrementNowArray(count, 3);\r
-                        break;\r
-                }\r
-            }\r
-            if (_quests.TryGetValue(428, out var q428))\r
-            {\r
-                var count = q428.Count;\r
-                switch (mid)\r
-                {\r
-                    case 4:\r
-                        IncrementNowArray(count, 0);\r
-                        break;\r
-                    case 101:\r
-                        IncrementNowArray(count, 1);\r
-                        break;\r
-                    case 102:\r
-                        IncrementNowArray(count, 2);\r
-                        break;\r
-                }\r
-            }\r
-        }\r
-\r
-        private void IncrementCount(QuestCount count)\r
-        {\r
-            count.Now++;\r
-            NeedSave = true;\r
-        }\r
-\r
-        private void AddCount(QuestCount count, int value)\r
-        {\r
-            count.Now += value;\r
-            NeedSave = true;\r
-        }\r
-\r
-        private void IncrementCount(int id)\r
-        {\r
-            AddCount(id, 1);\r
-        }\r
-\r
-        private void AddCount(int id, int value)\r
-        {\r
-            if (_quests.TryGetValue(id, out var quest))\r
-            {\r
-                quest.Count.Now += value;\r
-                NeedSave = true;\r
-            }\r
-        }\r
-\r
-        private void IncrementNowArray(QuestCount count, int n)\r
-        {\r
-            count.NowArray[n]++;\r
-            NeedSave = true;\r
+            RemoveQuest(QuestInterval.Weekly);\r
+            _countList.Remove(QuestInterval.Weekly);\r
         }\r
 \r
-        public void CountNyukyo() => IncrementCount(503);\r
-\r
-        public void CountCharge() => IncrementCount(504);\r
-\r
-        public void CountCreateItem()\r
-        {\r
-            IncrementCount(605);\r
-            IncrementCount(607);\r
-        }\r
+        private DateTime LastMonday => _now.Date.AddDays(-((6 + (int)_now.DayOfWeek) % 7));\r
 \r
-        public void CountCreateShip()\r
+        private void ResetMonthly()\r
         {\r
-            IncrementCount(606);\r
-            IncrementCount(608);\r
+            if (!CrossBoundary(new DateTime(_now.Year, _now.Month, 1, 5, 0, 0)))\r
+                return;\r
+            RemoveQuest(QuestInterval.Monthly);\r
+            _countList.Remove(QuestInterval.Monthly);\r
         }\r
 \r
-        public void InspectDestroyShip(string request)\r
+        private void ResetQuarterly()\r
         {\r
-            AddCount(609, HttpUtility.ParseQueryString(request)["api_ship_id"].Split(',').Length);\r
+            if (!CrossBoundary(QuarterlyBoundary.AddHours(5)))\r
+                return;\r
+            RemoveQuest(QuestInterval.Quarterly);\r
+            _countList.Remove(QuestInterval.Quarterly);\r
         }\r
 \r
-        public void CountRemodelSlot() => IncrementCount(619);\r
+        private DateTime QuarterlyBoundary =>\r
+            _now.Month / 3 == 0\r
+                ? new DateTime(_now.Year - 1, 12, 1)\r
+                : new DateTime(_now.Year, _now.Month / 3 * 3, 1);\r
 \r
-        public void InspectDestroyItem(string request, dynamic json)\r
+        private bool CrossBoundary(DateTime boundary)\r
         {\r
-            var values = HttpUtility.ParseQueryString(request);\r
-            var items = values["api_slotitem_ids"].Split(',')\r
-                .Select(id => _itemInfo.GetStatus(int.Parse(id)).Spec).ToArray();\r
-            IncrementCount(613); // 613: 資源の再利用\r
-            foreach (var quest in _quests.Values)\r
-            {\r
-                var count = quest.Count;\r
-                if (!(count.Spec is QuestDestroyItem destroy))\r
-                    continue;\r
-                if (destroy.Count(count, items))\r
-                    NeedSave = true;\r
-            }\r
-            if (_quests.TryGetValue(680, out var q680))\r
-            {\r
-                q680.Count.NowArray[0] += items.Count(spec => spec.Type == 21);\r
-                q680.Count.NowArray[1] += items.Count(spec => spec.Type == 12 || spec.Type == 13);\r
-                NeedSave = true;\r
-            }\r
+            return _lastReset < boundary && boundary <= _now;\r
         }\r
 \r
-        public void InspectPowerUp(dynamic json)\r
+        private void RemoveQuest(QuestInterval interval)\r
         {\r
-            if ((int)json.api_powerup_flag == 0)\r
-                return;\r
-            foreach (var quest in _quests.Values)\r
-            {\r
-                var count = quest.Count;\r
-                if (!(count.Spec is QuestPowerUp))\r
-                    continue;\r
-                IncrementCount(count);\r
-            }\r
+            foreach (var id in\r
+                (from kv in _quests\r
+                    where kv.Value.Count.Spec.Interval == interval || // 輸送5と空母3はカウンタを見ないとデイリーにならない\r
+                          kv.Value.Interval == interval\r
+                    select kv.Key).ToArray())\r
+                _quests.Remove(id);\r
         }\r
 \r
         public void InspectStop(string request)\r
@@ -912,7 +269,7 @@ namespace KancolleSniffer.Model
             NeedSave = true;\r
         }\r
 \r
-        public bool NeedSave { get; private set; }\r
+        public bool NeedSave { get; set; }\r
 \r
         public void SaveState(Status status)\r
         {\r
@@ -921,20 +278,21 @@ namespace KancolleSniffer.Model
             if (_quests != null)\r
                 status.QuestList = _quests.Values.ToArray();\r
             if (_countList != null)\r
-                status.QuestCountList = _countList.CountList.ToArray();\r
+                status.QuestCountList = _countList.NonZeroCountList.ToArray();\r
         }\r
 \r
         public void LoadState(Status status)\r
         {\r
             _lastReset = status.QuestLastReset;\r
             if (status.QuestCountList != null)\r
-                _countList.CountList = status.QuestCountList;\r
+                _countList.SetCountList(status.QuestCountList);\r
             if (status.QuestList != null)\r
             {\r
                 _quests.Clear();\r
-                foreach (var q in status.QuestList)\r
-                    AddQuest(q, false);\r
+                foreach (var quest in status.QuestList)\r
+                    SetQuest(quest);\r
             }\r
         }\r
     }\r
+\r
 }
\ No newline at end of file