OSDN Git Service

任務カウンターを実装する
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Fri, 17 Nov 2017 15:20:43 +0000 (00:20 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Sat, 27 Jan 2018 08:33:56 +0000 (17:33 +0900)
12 files changed:
KancolleSniffer.Test/KancolleSniffer.Test.csproj
KancolleSniffer.Test/QuestInfoTest.cs [new file with mode: 0644]
KancolleSniffer.Test/QuestInfoTest.txt [new file with mode: 0644]
KancolleSniffer.Test/logs
KancolleSniffer/BattleInfo.cs
KancolleSniffer/ItemInfo.cs
KancolleSniffer/MainForm.Designer.cs
KancolleSniffer/MainForm.cs
KancolleSniffer/QuestInfo.cs
KancolleSniffer/ShipInfo.cs
KancolleSniffer/Sniffer.cs
KancolleSniffer/Status.cs

index 8414e36..7c83474 100644 (file)
@@ -79,6 +79,7 @@
     <Compile Include="ErrorLogTest.cs" />\r
     <Compile Include="JsonTest.cs" />\r
     <Compile Include="NotificationManagerTest.cs" />\r
+    <Compile Include="QuestInfoTest.cs" />\r
     <Compile Include="ShipLabelTest.cs" />\r
     <Compile Include="SnifferTest.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
diff --git a/KancolleSniffer.Test/QuestInfoTest.cs b/KancolleSniffer.Test/QuestInfoTest.cs
new file mode 100644 (file)
index 0000000..181a4c6
--- /dev/null
@@ -0,0 +1,598 @@
+// Copyright (C) 2017 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using ExpressionToCodeLib;\r
+using Microsoft.VisualStudio.TestTools.UnitTesting;\r
+\r
+namespace KancolleSniffer.Test\r
+{\r
+    [TestClass]\r
+    public class QuestInfoTest\r
+    {\r
+        [TestMethod]\r
+        public void AdjustCount()\r
+        {\r
+            var count = new QuestCount\r
+            {\r
+                Spec = new QuestSpec {Max = 7},\r
+                Now = 3\r
+            };\r
+            count.AdjustCount(0);\r
+            PAssert.That(() => count.Now == 3);\r
+            count.AdjustCount(50);\r
+            PAssert.That(() => count.Now == 4);\r
+            count.AdjustCount(80);\r
+            PAssert.That(() => count.Now == 6);\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.Now == 7);\r
+            count.Now = 14;\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.Now == 14);\r
+            count.AdjustCount(80);\r
+            PAssert.That(() => count.Now == 6);\r
+            count.AdjustCount(50);\r
+            PAssert.That(() => count.Now == 5);\r
+            count.AdjustCount(0);\r
+            PAssert.That(() => count.Now == 3);\r
+        }\r
+\r
+        [TestMethod]\r
+        public void AdjustCountWithShift()\r
+        {\r
+            var count = new QuestCount\r
+            {\r
+                Spec = new QuestSpec {Max = 7, Shift = 1},\r
+                Now = 3\r
+            };\r
+            count.AdjustCount(0);\r
+            PAssert.That(() => count.Now == 2);\r
+            count.AdjustCount(50);\r
+            PAssert.That(() => count.Now == 3);\r
+            count.AdjustCount(80);\r
+            PAssert.That(() => count.Now == 6);\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.Now == 7);\r
+            count.Now = 14;\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.Now == 14);\r
+            count.AdjustCount(80);\r
+            PAssert.That(() => count.Now == 6);\r
+            count.AdjustCount(50);\r
+            PAssert.That(() => count.Now == 5);\r
+            count.AdjustCount(0);\r
+            PAssert.That(() => count.Now == 2);\r
+        }\r
+\r
+        [TestMethod]\r
+        public void AdjestCountNowArray()\r
+        {\r
+            var count = new QuestCount\r
+            {\r
+                Spec = new QuestSpec {MaxArray = new[] {36, 6, 24, 12}},\r
+                NowArray = new[] {1, 2, 3, 4}\r
+            };\r
+            count.AdjustCount(50);\r
+            PAssert.That(() => count.NowArray.SequenceEqual(new[] {1, 2, 3, 4}));\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.NowArray.SequenceEqual(new[] {36, 6, 24, 12}));\r
+            count.NowArray = new[] {38, 12, 19, 12};\r
+            count.AdjustCount(100);\r
+            PAssert.That(() => count.NowArray.SequenceEqual(new[] {38, 12, 24, 12}));\r
+        }\r
+\r
+        [TestMethod]\r
+        public void ResetQuest()\r
+        {\r
+            var queue = new Queue<DateTime>(new[]\r
+            {\r
+                new DateTime(2017, 11, 1, 5, 0, 0), new DateTime(2017, 11, 6, 5, 0, 0),\r
+                new DateTime(2017, 12, 1, 5, 0, 0)\r
+            });\r
+            var questInfo = new QuestInfo(null, null, () => queue.Dequeue());\r
+            var status = new Status\r
+            {\r
+                QuestCountList = new[]\r
+                {\r
+                    new QuestCount {Id = 201, Now = 1}, new QuestCount {Id = 213, Now = 1},\r
+                    new QuestCount {Id = 265, Now = 1}, new QuestCount {Id = 822, Now = 1}\r
+                },\r
+                QuestLastReset = new DateTime(2017, 10, 31, 5, 0, 0)\r
+            };\r
+            questInfo.LoadState(status);\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                    {new {api_no = 201, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}}\r
+            }));\r
+            questInfo.SaveState(status);\r
+            PAssert.That(() =>\r
+                status.QuestCountList.Select(qc => new {qc.Id, qc.Now}).SequenceEqual(new[]\r
+                    {new {Id = 213, Now = 1}, new {Id = 822, Now = 1}})); // デイリーとマンスリーが消える\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                    {new {api_no = 201, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}}\r
+            }));\r
+            questInfo.SaveState(status);\r
+            PAssert.That(() =>\r
+                status.QuestCountList.Select(qc => new {qc.Id, qc.Now}).SequenceEqual(new[]\r
+                    {new {Id = 822, Now = 1}})); // ウィークリーが消える\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                    {new {api_no = 201, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}}\r
+            }));\r
+            questInfo.SaveState(status);\r
+            PAssert.That(() => status.QuestCountList.Length == 0); // クォータリーが消える\r
+        }\r
+\r
+        private JsonObject Js(object obj) => JsonObject.CreateJsonObject(obj);\r
+\r
+        /// <summary>\r
+        /// 201: 敵艦隊を撃滅せよ!\r
+        /// 210: 敵艦隊を10回邀撃せよ!\r
+        /// 214: あ号\r
+        /// 216: 敵艦隊主力を撃滅せよ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void BattleResult_201_216_210_214()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 201, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 210, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 214, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 216, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.InspectMapStart(Js(new\r
+            {\r
+                api_maparea_id = 1,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 4\r
+            }));\r
+            var quests = questInfo.Quests;\r
+            // 出撃カウント\r
+            PAssert.That(() => quests[2].Id == 214 && quests[2].Count.NowArray[0] == 1);\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            // 道中S勝利\r
+            PAssert.That(() => quests.Select(q => new {q.Id, q.Count.Now}).SequenceEqual(new[]\r
+            {\r
+                new {Id = 201, Now = 1}, new {Id = 210, Now = 1},\r
+                new {Id = 214, Now = 0}, new {Id = 216, Now = 1}\r
+            }));\r
+            PAssert.That(() => quests[2].Id == 214 &&\r
+                               quests[2].Count.NowArray.SequenceEqual(new[] {1, 1, 0, 0}));\r
+\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 1,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 5\r
+            }));\r
+            // ボスB勝利\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "B"}));\r
+            PAssert.That(() => quests.Select(q => new {q.Id, q.Count.Now}).SequenceEqual(new[]\r
+            {\r
+                new {Id = 201, Now = 2}, new {Id = 210, Now = 2},\r
+                new {Id = 214, Now = 0}, new {Id = 216, Now = 2}\r
+            }));\r
+            // ボス敗北\r
+            PAssert.That(() => quests[2].Id == 214 && quests[2].Count.NowArray.SequenceEqual(new[] {1, 1, 1, 1}));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "C"}));\r
+            PAssert.That(() => quests.Select(q => new {q.Id, q.Count.Now}).SequenceEqual(new[]\r
+            {\r
+                new {Id = 201, Now = 2}, new {Id = 210, Now = 3},\r
+                new {Id = 214, Now = 0}, new {Id = 216, Now = 2}\r
+            }));\r
+            PAssert.That(() => quests[2].Id == 214 && quests[2].Count.NowArray.SequenceEqual(new[] {1, 1, 2, 1}));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 211: 敵空母を3隻撃沈せよ!\r
+        /// 212: 敵輸送船団を叩け!\r
+        /// 213: 海上通商破壊作戦\r
+        /// 218: 敵補給艦を3隻撃沈せよ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void BattleResult_211_212_218_213_220_221()\r
+        {\r
+            var battleInfo = new BattleInfo(null, null);\r
+            var questInfo = new QuestInfo(null, battleInfo, () => new DateTime(2015, 1, 1)) {AcceptMax = 6};\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 211, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 212, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 213, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 218, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 220, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 221, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+            // 補給艦1隻と空母2隻\r
+            battleInfo.InjectEnemyResultStatus(new[]\r
+            {\r
+                new ShipStatus {NowHp = 0, MaxHp = 130, Spec = new ShipSpec {Id = 1558, ShipType = 15}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 90, Spec = new ShipSpec {Id = 1543, ShipType = 8}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 90, Spec = new ShipSpec {Id = 1543, ShipType = 8}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 96, Spec = new ShipSpec {Id = 1528, ShipType = 11}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 70, Spec = new ShipSpec {Id = 1523, ShipType = 7}},\r
+                new ShipStatus {NowHp = 1, MaxHp = 70, Spec = new ShipSpec {Id = 1523, ShipType = 7}}\r
+            }, new ShipStatus[0]);\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "A"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[]\r
+                    {\r
+                        new {Id = 211, Now = 2}, new {Id = 212, Now = 1}, new {Id = 213, Now = 1},\r
+                        new {Id = 218, Now = 1}, new {Id = 220, Now = 2}, new {Id = 221, Now = 1}\r
+                    }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 228: 海上護衛戦\r
+        /// 230: 敵潜水艦を制圧せよ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void BattleResult_228_230()\r
+        {\r
+            var battleInfo = new BattleInfo(null, null);\r
+            var questInfo = new QuestInfo(null, battleInfo, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 228, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 230, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                }\r
+            }));\r
+            // 潜水艦3\r
+            battleInfo.InjectEnemyResultStatus(new[]\r
+            {\r
+                new ShipStatus {NowHp = 0, MaxHp = 27, Spec = new ShipSpec {Id = 1532, ShipType = 13}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 19, Spec = new ShipSpec {Id = 1530, ShipType = 13}},\r
+                new ShipStatus {NowHp = 0, MaxHp = 19, Spec = new ShipSpec {Id = 1530, ShipType = 13}},\r
+            }, new ShipStatus[0]);\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[]\r
+                    {\r
+                        new {Id = 228, Now = 3}, new {Id = 230, Now = 3}\r
+                    }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 226: 南西諸島海域の制海権を握れ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void BattleResult_226()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 226, api_category = 2, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.InspectMapStart(Js(new\r
+            {\r
+                api_maparea_id = 2,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 4\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[] {new {Id = 226, Now = 0}}));\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 2,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[] {new {Id = 226, Now = 1}}));\r
+            questInfo.InspectMapStart(Js(new\r
+            {\r
+                api_maparea_id = 2,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 4\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[] {new {Id = 226, Now = 1}}));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 822: 沖ノ島海域迎撃戦\r
+        /// 854: 戦果拡張任務!「Z作戦」前段作戦\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void BattleResult_822_854()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 822, api_category = 8, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 854, api_category = 8, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 2,\r
+                api_mapinfo_no = 4,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "A"}));\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 6,\r
+                api_mapinfo_no = 1,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "A"}));\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 6,\r
+                api_mapinfo_no = 3,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "A"}));\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 6,\r
+                api_mapinfo_no = 4,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() => questInfo.Quests[1].Count.NowArray.SequenceEqual(new[] {1, 1, 1, 1}));\r
+            PAssert.That(() => questInfo.Quests[0].Count.Now == 0);\r
+            questInfo.InspectMapNext(Js(new\r
+            {\r
+                api_maparea_id = 2,\r
+                api_mapinfo_no = 4,\r
+                api_event_id = 5\r
+            }));\r
+            questInfo.InspectBattleResult(Js(new {api_win_rank = "S"}));\r
+            PAssert.That(() => questInfo.Quests[1].Count.NowArray.SequenceEqual(new[] {2, 1, 1, 1}));\r
+            PAssert.That(() => questInfo.Quests[0].Count.Now == 1);\r
+        }\r
+\r
+        /// <summary>\r
+        /// 302: 大規模演習\r
+        /// 303: 「演習」で練度向上!\r
+        /// 304: 「演習」で他提督を圧倒せよ!\r
+        /// 311: 精鋭艦隊演習\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void PracticeResult_303_304_302_311()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 302, api_category = 3, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 303, api_category = 3, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 304, api_category = 3, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 311, api_category = 3, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.InspectPracticeResult(Js(new {api_win_rank = "C"}));\r
+            questInfo.InspectPracticeResult(Js(new {api_win_rank = "A"}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[]\r
+                    {\r
+                        new {Id = 302, Now = 1}, new {Id = 303, Now = 2}, new {Id = 304, Now = 1},\r
+                        new {Id = 311, Now = 1}\r
+                    }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 402: 「遠征」を3回成功させよう!\r
+        /// 403: 「遠征」を10回成功させよう!\r
+        /// 404: 大規模遠征作戦、発令!\r
+        /// 410: 南方への輸送作戦を成功させよ!\r
+        /// 411: 南方への鼠輸送を継続実施せよ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void MissionResult_402_403_404_410_411()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 402, api_category = 4, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 403, api_category = 4, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 404, api_category = 4, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 410, api_category = 4, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 411, api_category = 4, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.InspectDeck(Js(\r
+                new[]\r
+                {\r
+                    new {api_id = 2, api_mission = new[] {2, 6}},\r
+                    new {api_id = 3, api_mission = new[] {2, 37}},\r
+                    new {api_id = 4, api_mission = new[] {2, 2}}\r
+                }));\r
+            questInfo.InspectMissionResult("api%5Fdeck%5Fid=2", Js(new {api_clear_result = 1}));\r
+            questInfo.InspectMissionResult("api%5Fdeck%5Fid=3", Js(new {api_clear_result = 2}));\r
+            questInfo.InspectMissionResult("api%5Fdeck%5Fid=4", Js(new {api_clear_result = 0}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[]\r
+                    {\r
+                        new {Id = 402, Now = 2}, new {Id = 403, Now = 2}, new {Id = 404, Now = 2},\r
+                        new {Id = 410, Now = 1}, new {Id = 411, Now = 1}\r
+                    }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 503: 艦隊大整備!\r
+        /// 504: 艦隊酒保祭り!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void Powerup_503_504()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 503, api_category = 5, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 504, api_category = 5, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.CountNyukyo();\r
+            questInfo.CountCharge();\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[] {new {Id = 503, Now = 1}, new {Id = 504, Now = 1}}));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 605: 新装備「開発」指令\r
+        /// 606: 新造艦「建造」指令\r
+        /// 607: 装備「開発」集中強化!\r
+        /// 608: 艦娘「建造」艦隊強化!\r
+        /// 609: 軍縮条約対応!\r
+        /// 619: 装備の改修強化\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void Kousyou_605_606_607_608_609_619()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1)) {AcceptMax = 6};\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 605, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 606, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 607, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 608, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 609, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 619, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+\r
+            questInfo.CountCreateItem();\r
+            questInfo.CountCreateShip();\r
+            questInfo.InspectDestroyShip("api%5Fship%5Fid=98159%2C98166%2C98168&api%5Fverno=1");\r
+            questInfo.CountRemodelSlot();\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[]\r
+                    {\r
+                        new {Id = 605, Now = 1}, new {Id = 606, Now = 1}, new {Id = 607, Now = 1},\r
+                        new {Id = 608, Now = 1}, new {Id = 609, Now = 3}, new {Id = 619, Now = 1}\r
+                    }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 613: 資源の再利用\r
+        /// 638: 対空機銃量産\r
+        /// 673: 装備開発力の整備\r
+        /// 674: 工廠環境の整備\r
+        /// 675: 運用装備の統合整備\r
+        /// 676: 装備開発力の集中整備\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void DestroyItem_613_638_673_674_675_676()\r
+        {\r
+            var itemInfo = new ItemInfo();\r
+            var questInfo = new QuestInfo(itemInfo, null, () => new DateTime(2015, 1, 1)) {AcceptMax = 6};\r
+\r
+            itemInfo.InjectItemSpec(new[]\r
+            {\r
+                new ItemSpec {Id = 1, Name = "12cm単装砲", Type = 1},\r
+                new ItemSpec {Id = 37, Name = "7.7mm機銃", Type = 21},\r
+                new ItemSpec {Id = 19, Name = "九六式艦戦", Type = 6},\r
+                new ItemSpec {Id = 4, Name = "14cm単装砲", Type = 2},\r
+                new ItemSpec {Id = 11, Name = "15.2cm単装砲", Type = 4},\r
+                new ItemSpec {Id = 75, Name = "ドラム缶(輸送用)", Type = 30}\r
+            });\r
+            itemInfo.InjectItems(new[] {1, 37, 19, 4, 11, 75});\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 613, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 638, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 673, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 674, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 675, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 676, api_category = 6, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+            questInfo.InspectDestroyItem("api%5Fslotitem%5Fids=1%2C2%2C3%2C4%2C5%2C6&api%5Fverno=1", null);\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now}).Take(4).SequenceEqual(new[]\r
+                {\r
+                    new {Id = 613, Now = 1}, new {Id = 638, Now = 1},\r
+                    new {Id = 673, Now = 1}, new {Id = 674, Now = 1}\r
+                }));\r
+            var q675 = questInfo.Quests[4];\r
+            PAssert.That(() => q675.Id == 675 && q675.Count.NowArray.SequenceEqual(new[] {1, 1}));\r
+            var q676 = questInfo.Quests[5];\r
+            PAssert.That(() => q676.Id == 676 && q676.Count.NowArray.SequenceEqual(new[] {1, 1, 1}));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 702: 艦の「近代化改修」を実施せよ!\r
+        /// 703: 「近代化改修」を進め、戦備を整えよ!\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void Powerup_702_703()\r
+        {\r
+            var questInfo = new QuestInfo(null, null, () => new DateTime(2015, 1, 1));\r
+\r
+            questInfo.InspectQuestList(Js(new\r
+            {\r
+                api_list = new[]\r
+                {\r
+                    new {api_no = 702, api_category = 7, api_state = 2, api_title = "", api_progress_flag = 0},\r
+                    new {api_no = 703, api_category = 7, api_state = 2, api_title = "", api_progress_flag = 0}\r
+                }\r
+            }));\r
+            questInfo.InspectPowerup(Js(new {api_powerup_flag = 1}));\r
+            PAssert.That(() =>\r
+                questInfo.Quests.Select(q => new {q.Id, q.Count.Now})\r
+                    .SequenceEqual(new[] {new {Id = 702, Now = 1}, new {Id = 703, Now = 1}}));\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/KancolleSniffer.Test/QuestInfoTest.txt b/KancolleSniffer.Test/QuestInfoTest.txt
new file mode 100644 (file)
index 0000000..41bcc45
--- /dev/null
@@ -0,0 +1,13 @@
+BattleResult_201_214\r
+  api_get_member/questlist: {"api_list":[{"api_no":201,"api_category":2,"api_state":2,"api_title":"","api_progress_flag":0},{"api_no":214,"api_category":2,"api_state":2,"api_title":"","api_progress_flag":0}]}\r
+  api_req_map/start: {"api_maparea_id":1,"api_mapinfo_no":1,"api_no":1,"api_bosscell_no":3}\r
+  api_req_sortie/battleresult1: {"api_win_rank":"S"}\r
+  api_req_map/next: {"api_maparea_id":1,"api_mapinfo_no":1,"api_no":3,"api_bosscell_no":3}\r
+  api_req_sortie/battleresult2: {"api_win_rank":"B"}\r
+\r
+DestroyItem_613_638\r
+  api_start2.api_mst_slotitem: {"api_mst_slotitem_equiptype":[{"api_id":21,"api_name":"対空機銃","api_show_flg":1}],"api_mst_slotitem":[{"api_id":37,"api_sortno":37,"api_name":"7.7mm機銃","api_type":[4,6,21,15,0],"api_taik":0,"api_souk":0,"api_houg":0,"api_raig":0,"api_soku":0,"api_baku":0,"api_tyku":2,"api_tais":0,"api_atap":0,"api_houm":0,"api_raim":0,"api_houk":1,"api_raik":0,"api_bakk":0,"api_saku":0,"api_sakb":0,"api_luck":0,"api_leng":0,"api_rare":0,"api_broken":[0,1,1,0],"api_usebull":"0"}],"api_mst_useitem":[]}\r
+  api_get_member/questlist: {"api_list":[{"api_no":613,"api_category":6,"api_type":2,"api_state":2,"api_title":"","api_progress_flag":0},{"api_no":638,"api_category":6,"api_type":2,"api_state":2,"api_title":"","api_progress_flag":0}]}\r
+  api_get_member/slot_item: [{"api_id":156730,"api_slotitem_id":37,"api_locked":0,"api_level":0},{"api_id":156775,"api_slotitem_id":37,"api_locked":0,"api_level":0}]\r
+  api_req_kousyou/destroyitem2.request: api%5Fslotitem%5Fids=156730%2C156775&api%5Fverno=1\r
+  api_req_kousyou/destroyitem2: {"api_result":1,"api_result_msg":"成功","api_data":{"api_get_material":[0,2,2,0]}}\r
index f9012c8..fec7ef9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f9012c80155a0960371c5519888496d58cbb4c30
+Subproject commit fec7ef9ba5ccda7d066e18b16558a464678bb5de
index 7164dff..c1d22c8 100644 (file)
@@ -681,5 +681,14 @@ namespace KancolleSniffer
                 return BattleResultRank.E;\r
             return BattleResultRank.D;\r
         }\r
+\r
+        /// <summary>\r
+        /// テスト専用\r
+        /// </summary>\r
+        public void InjectEnemyResultStatus(ShipStatus[] enemy, ShipStatus[] guard)\r
+        {\r
+            EnemyResultStatus = enemy;\r
+            EnemyGuardResultStatus = guard;\r
+        }\r
     }\r
 }
\ No newline at end of file
index 7dccaf1..934b6f8 100644 (file)
@@ -139,6 +139,8 @@ namespace KancolleSniffer
 \r
         public bool IsRepairFacility => Type == 31;\r
 \r
+        public bool IsAntiAirGun => Type == 21;\r
+\r
         public double ContactTriggerRate\r
         {\r
             get\r
@@ -728,7 +730,13 @@ namespace KancolleSniffer
 \r
         public string GetUseItemName(int id) => _useItemName[id];\r
 \r
-        public IEnumerable<ItemStatus> InjectItems(IEnumerable<int> itemIds)\r
+        public void InjectItemSpec(IEnumerable<ItemSpec> specs)\r
+        {\r
+            foreach (var spec in specs)\r
+                _itemSpecs.Add(spec.Id, spec);\r
+        }\r
+\r
+        public ItemStatus[] InjectItems(IEnumerable<int> itemIds)\r
         {\r
             var id = _itemInfo.Keys.Count + 1;\r
             return itemIds.Select(itemId =>\r
@@ -741,7 +749,7 @@ namespace KancolleSniffer
                 var item = new ItemStatus {Id = id++, Spec = spec};\r
                 _itemInfo.Add(item.Id, item);\r
                 return item;\r
-            });\r
+            }).ToArray();\r
         }\r
     }\r
 }
\ No newline at end of file
index ab0829d..c031fad 100644 (file)
@@ -109,6 +109,12 @@ namespace KancolleSniffer
             this.label13 = new System.Windows.Forms.Label();\r
             this.timerMain = new System.Windows.Forms.Timer(this.components);\r
             this.panel3 = new System.Windows.Forms.Panel();\r
+            this.labelQuestCount1 = new KancolleSniffer.ShipLabel();\r
+            this.labelQuestCount2 = new KancolleSniffer.ShipLabel();\r
+            this.labelQuestCount3 = new KancolleSniffer.ShipLabel();\r
+            this.labelQuestCount4 = new KancolleSniffer.ShipLabel();\r
+            this.labelQuestCount5 = new KancolleSniffer.ShipLabel();\r
+            this.labelQuestCount6 = new KancolleSniffer.ShipLabel();\r
             this.labelQuestColor6 = new System.Windows.Forms.Label();\r
             this.labelQuestColor5 = new System.Windows.Forms.Label();\r
             this.labelQuestColor4 = new System.Windows.Forms.Label();\r
@@ -802,6 +808,12 @@ namespace KancolleSniffer
             // panel3\r
             // \r
             this.panel3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\r
+            this.panel3.Controls.Add(this.labelQuestCount1);\r
+            this.panel3.Controls.Add(this.labelQuestCount2);\r
+            this.panel3.Controls.Add(this.labelQuestCount3);\r
+            this.panel3.Controls.Add(this.labelQuestCount4);\r
+            this.panel3.Controls.Add(this.labelQuestCount5);\r
+            this.panel3.Controls.Add(this.labelQuestCount6);\r
             this.panel3.Controls.Add(this.labelQuestColor6);\r
             this.panel3.Controls.Add(this.labelQuestColor5);\r
             this.panel3.Controls.Add(this.labelQuestColor4);\r
@@ -825,6 +837,72 @@ namespace KancolleSniffer
             this.panel3.Size = new System.Drawing.Size(220, 94);\r
             this.panel3.TabIndex = 13;\r
             // \r
+            // labelQuestCount1\r
+            // \r
+            this.labelQuestCount1.AnchorRight = true;\r
+            this.labelQuestCount1.AutoSize = true;\r
+            this.labelQuestCount1.Location = new System.Drawing.Point(191, 3);\r
+            this.labelQuestCount1.Name = "labelQuestCount1";\r
+            this.labelQuestCount1.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount1.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount1.TabIndex = 54;\r
+            this.labelQuestCount1.UseMnemonic = false;\r
+            // \r
+            // labelQuestCount2\r
+            // \r
+            this.labelQuestCount2.AnchorRight = true;\r
+            this.labelQuestCount2.AutoSize = true;\r
+            this.labelQuestCount2.Location = new System.Drawing.Point(191, 18);\r
+            this.labelQuestCount2.Name = "labelQuestCount2";\r
+            this.labelQuestCount2.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount2.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount2.TabIndex = 53;\r
+            this.labelQuestCount2.UseMnemonic = false;\r
+            // \r
+            // labelQuestCount3\r
+            // \r
+            this.labelQuestCount3.AnchorRight = true;\r
+            this.labelQuestCount3.AutoSize = true;\r
+            this.labelQuestCount3.Location = new System.Drawing.Point(191, 33);\r
+            this.labelQuestCount3.Name = "labelQuestCount3";\r
+            this.labelQuestCount3.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount3.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount3.TabIndex = 52;\r
+            this.labelQuestCount3.UseMnemonic = false;\r
+            // \r
+            // labelQuestCount4\r
+            // \r
+            this.labelQuestCount4.AnchorRight = true;\r
+            this.labelQuestCount4.AutoSize = true;\r
+            this.labelQuestCount4.Location = new System.Drawing.Point(191, 48);\r
+            this.labelQuestCount4.Name = "labelQuestCount4";\r
+            this.labelQuestCount4.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount4.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount4.TabIndex = 51;\r
+            this.labelQuestCount4.UseMnemonic = false;\r
+            // \r
+            // labelQuestCount5\r
+            // \r
+            this.labelQuestCount5.AnchorRight = true;\r
+            this.labelQuestCount5.AutoSize = true;\r
+            this.labelQuestCount5.Location = new System.Drawing.Point(191, 63);\r
+            this.labelQuestCount5.Name = "labelQuestCount5";\r
+            this.labelQuestCount5.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount5.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount5.TabIndex = 50;\r
+            this.labelQuestCount5.UseMnemonic = false;\r
+            // \r
+            // labelQuestCount6\r
+            // \r
+            this.labelQuestCount6.AnchorRight = true;\r
+            this.labelQuestCount6.AutoSize = true;\r
+            this.labelQuestCount6.Location = new System.Drawing.Point(191, 78);\r
+            this.labelQuestCount6.Name = "labelQuestCount6";\r
+            this.labelQuestCount6.PresetColor = System.Drawing.Color.Empty;\r
+            this.labelQuestCount6.Size = new System.Drawing.Size(0, 12);\r
+            this.labelQuestCount6.TabIndex = 49;\r
+            this.labelQuestCount6.UseMnemonic = false;\r
+            // \r
             // labelQuestColor6\r
             // \r
             this.labelQuestColor6.Location = new System.Drawing.Point(2, 79);\r
@@ -1362,6 +1440,7 @@ namespace KancolleSniffer
             this.panel2.ResumeLayout(false);\r
             this.panel2.PerformLayout();\r
             this.panel3.ResumeLayout(false);\r
+            this.panel3.PerformLayout();\r
             this.contextMenuStripNotifyIcon.ResumeLayout(false);\r
             this.contextMenuStripMain.ResumeLayout(false);\r
             this.ResumeLayout(false);\r
@@ -1493,6 +1572,12 @@ namespace KancolleSniffer
         private RepairListForMain panelRepairList;\r
         private System.Windows.Forms.Panel panel7Ships;\r
         private System.Windows.Forms.LinkLabel linkLabelGuide;\r
+        private ShipLabel labelQuestCount1;\r
+        private ShipLabel labelQuestCount2;\r
+        private ShipLabel labelQuestCount3;\r
+        private ShipLabel labelQuestCount4;\r
+        private ShipLabel labelQuestCount5;\r
+        private ShipLabel labelQuestCount6;\r
     }\r
 }\r
 \r
index 3a24ab9..0f659e1 100644 (file)
@@ -897,6 +897,11 @@ namespace KancolleSniffer
                 labelQuestColor6\r
             };\r
             var name = new[] {labelQuest1, labelQuest2, labelQuest3, labelQuest4, labelQuest5, labelQuest6};\r
+            var count = new[]\r
+            {\r
+                labelQuestCount1, labelQuestCount2, labelQuestCount3, labelQuestCount4, labelQuestCount5,\r
+                labelQuestCount6\r
+            };\r
             var progress = new[]\r
                 {labelProgress1, labelProgress2, labelProgress3, labelProgress4, labelProgress5, labelProgress6};\r
             var quests = _sniffer.Quests;\r
@@ -907,11 +912,23 @@ namespace KancolleSniffer
                     category[i].BackColor = quests[i].Color;\r
                     name[i].Text = quests[i].Name;\r
                     progress[i].Text = $"{quests[i].Progress:D}%";\r
+                    var c = quests[i].Count;\r
+                    if (c.Id == 0)\r
+                    {\r
+                        count[i].Text = "";\r
+                        count[i].ForeColor = Color.Black;\r
+                        continue;\r
+                    }\r
+                    count[i].Text = c.NowArray != null ? $"{string.Join("|", c.NowArray)}" : $"{c.Now}/{c.Max}";\r
+                    count[i].ForeColor =\r
+                        (c.NowArray?.Zip(c.Spec.MaxArray, (n, m) => n >= m).All(x => x) ?? c.Now >= c.Spec.Max)\r
+                            ? CUDColor.Green\r
+                            : Color.Black;\r
                 }\r
                 else\r
                 {\r
                     category[i].BackColor = DefaultBackColor;\r
-                    name[i].Text = progress[i].Text = "";\r
+                    name[i].Text = count[i].Text = progress[i].Text = "";\r
                 }\r
             }\r
         }\r
index 626e0d3..b6903d3 100644 (file)
@@ -17,21 +17,275 @@ using System.Collections.Generic;
 using System.Drawing;\r
 using System.Linq;\r
 using System.Windows.Forms;\r
+using System.Xml.Serialization;\r
+using static System.Math;\r
 \r
 namespace KancolleSniffer\r
 {\r
-    public struct QuestStatus\r
+    public class QuestStatus\r
     {\r
+        public int Id { get; set; }\r
         public int Category { get; set; }\r
         public string Name { get; set; }\r
+        public QuestCount Count { get; set; }\r
         public int Progress { get; set; }\r
         public Color Color { get; set; }\r
     }\r
 \r
-    public class QuestInfo\r
+    public enum QuestInterval\r
+    {\r
+        Other,\r
+        Daily,\r
+        Weekly,\r
+        Monthly,\r
+        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
+    }\r
+\r
+    public class QuestSortie : QuestSpec\r
+    {\r
+        public string Rank { get; set; }\r
+        public int[] Maps { get; set; }\r
+        public int[] ShipTypes { 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[] Items { get; set; }\r
+        public bool Check(int id) => Items == null || Items.Contains(id);\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
+        public int Max => Spec.Max;\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, (n, m) => Max(n, m)).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 = Max + Spec.Shift;\r
+            var low = (int)Ceiling(max * progress / 100.0);\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
+\r
+    // @formatter:off\r
+    public class QuestCountList\r
+    {\r
+        private const QuestInterval Daily = QuestInterval.Daily;\r
+        private const QuestInterval Weekly = QuestInterval.Weekly;\r
+        private const QuestInterval Monthly = QuestInterval.Monthly;\r
+        private const QuestInterval Quarterly = QuestInterval.Quarterly;\r
+\r
+        /// <summary>\r
+        /// このテーブルは七四式電子観測儀を参考に作成した。\r
+        /// https://github.com/andanteyk/ElectronicObserver/blob/develop/ElectronicObserver/Data/Quest/QuestProgressManager.cs\r
+        /// </summary>\r
+        private static readonly Dictionary<int, QuestSpec> QuestSpecs = new Dictionary<int, QuestSpec>\r
+        {\r
+            {201, new QuestSortie {Interval = Daily, Max = 1, Rank = "B"}}, // 201: 敵艦隊を撃滅せよ!\r
+            {216, new QuestSortie {Interval = Daily, Max = 1, Rank = "B"}}, // 216: 敵艦隊主力を撃滅せよ!\r
+            {210, new QuestSortie {Interval = Daily, Max = 10}}, // 210: 敵艦隊を10回邀撃せよ!\r
+            {211, new QuestEnemyType {Interval = Daily, Max = 3, EnemyType = new[] {7, 11}}}, // 211: 敵空母を3隻撃沈せよ!\r
+            {212, new QuestEnemyType {Interval = Daily, Max = 5, EnemyType = new[] {15}}}, // 212: 敵輸送船団を叩け!\r
+            {218, new QuestEnemyType {Interval = Daily, Max = 3, EnemyType = new[] {15}}}, // 218: 敵補給艦を3隻撃沈せよ!\r
+            {226, new QuestSortie {Interval = Daily, Max = 5, Rank = "B", Maps = new[] {21, 22, 23, 24, 25}}}, // 226: 南西諸島海域の制海権を握れ!\r
+            {230, new QuestEnemyType {Interval = Daily, Max = 6, EnemyType = new[] {13}}}, // 230: 敵潜水艦を制圧せよ!\r
+\r
+            {213, new QuestEnemyType {Interval = Weekly, Max = 20, EnemyType = new[] {15}}}, // 213: 海上通商破壊作戦\r
+            {214, new QuestSpec {Interval = Weekly, MaxArray = new[] {36, 6, 24, 12}}}, // 214: あ号作戦\r
+            {220, new QuestEnemyType {Interval = Weekly, Max = 20, EnemyType = new[] {7, 11}}}, // 220: い号作戦\r
+            {221, new QuestEnemyType {Interval = Weekly, Max = 50, EnemyType = new[] {15}}}, // 221: ろ号作戦\r
+            {228, new QuestEnemyType {Interval = Weekly, Max = 15, EnemyType = new[] {13}}}, // 228: 海上護衛戦\r
+            {229, new QuestSortie {Interval = Weekly, Max = 12, Rank = "B", Maps = new[] {41, 42, 43, 44, 45}}}, // 229: 敵東方艦隊を撃滅せよ!\r
+            {241, new QuestSortie {Interval = Weekly, Max = 5, Rank = "B", Maps = new[] {33, 34, 35}}}, // 241: 敵北方艦隊主力を撃滅せよ!\r
+            {242, new QuestSortie {Interval = Weekly, Max = 1, Rank = "B", Maps = new[] {44}}}, // 242: 敵東方中枢艦隊を撃破せよ!\r
+            {243, new QuestSortie {Interval = Weekly, Max = 2, Rank = "B", Maps = new[] {52}}}, // 243: 南方海域珊瑚諸島沖の制空権を握れ!\r
+            {256, new QuestSortie {Interval = Monthly, Max = 3, Rank = "S", Maps = new[] {61}}}, // 256: 「潜水艦隊」出撃せよ!\r
+            {261, new QuestSortie {Interval = Weekly, Max = 3, Rank = "A", Maps = new[] {15}}}, // 261: 海上輸送路の安全確保に努めよ!\r
+            {265, new QuestSortie {Interval = Monthly, Max = 10, Rank = "A", Maps = new[] {15}}}, // 265: 海上護衛強化月間\r
+\r
+            {822, new QuestSortie {Interval = Quarterly, Max = 2, Rank = "S", Maps = new[] {24}}}, // 822: 沖ノ島海域迎撃戦\r
+            {854, new QuestSpec {Interval = Quarterly, MaxArray = new[] {1, 1, 1, 1}}}, // 854: 戦果拡張任務!「Z作戦」前段作戦\r
+\r
+            {303, new QuestPractice {Interval = Daily, Max = 3, Win = false}}, // 303: 「演習」で練度向上!\r
+            {304, new QuestPractice {Interval = Daily, Max = 5, Win = true}}, // 304: 「演習」で他提督を圧倒せよ!\r
+            {302, new QuestPractice {Interval = Weekly, Max = 20, Win = true}}, // 302: 大規模演習\r
+            {311, new QuestPractice {Interval = Daily, Max = 7, Win = true}}, // 311: 精鋭艦隊演習\r
+\r
+            {402, new QuestMission {Interval = Daily, Max = 3}}, // 402: 「遠征」を3回成功させよう!\r
+            {403, new QuestMission {Interval = Daily, Max = 10}}, // 403: 「遠征」を10回成功させよう!\r
+            {404, new QuestMission {Interval = Weekly, Max = 30}}, // 404: 大規模遠征作戦、発令!\r
+            {410, new QuestMission {Interval = Weekly, Max = 1, Ids = new[] {37, 38}}}, // 410: 南方への輸送作戦を成功させよ!\r
+            {411, new QuestMission {Interval = Weekly, Max = 6, Shift = 1, Ids = new[] {37, 38}}}, // 411: 南方への鼠輸送を継続実施せよ!\r
+            {424, new QuestMission {Interval = Monthly, Max = 4, Shift = 1, Ids = new[] {5}}}, // 424: 輸送船団護衛を強化せよ!\r
+\r
+            {503, new QuestSpec {Interval = Daily, Max = 5}}, // 503: 艦隊大整備!\r
+            {504, new QuestSpec {Interval = Daily, Max = 15}}, // 504: 艦隊酒保祭り!\r
+\r
+            {605, new QuestSpec {Interval = Daily, Max = 1}}, // 605: 新装備「開発」指令\r
+            {606, new QuestSpec {Interval = Daily, Max = 1}}, // 606: 新造艦「建造」指令\r
+            {607, new QuestSpec {Interval = Daily, Max = 3, Shift = 1}}, // 607: 装備「開発」集中強化!\r
+            {608, new QuestSpec {Interval = Daily, Max = 3, Shift = 1}}, // 608: 艦娘「建造」艦隊強化!\r
+            {609, new QuestSpec {Interval = Daily, Max = 2}}, // 609: 軍縮条約対応!\r
+            {619, new QuestSpec {Interval = Daily, Max = 1}}, // 619: 装備の改修強化\r
+\r
+            {613, new QuestSpec {Interval = Weekly, Max = 24}}, // 613: 資源の再利用\r
+            {638, new QuestDestroyItem {Interval = Weekly, Max = 6, Items = new[] {21}}}, // 638: 対空機銃量産\r
+            {673, new QuestDestroyItem {Interval = Daily, Max = 4, Items = new[] {1}, Shift = 1}}, // 673: 装備開発力の整備\r
+            {674, new QuestDestroyItem {Interval = Daily, Max = 3, Items = new[] {21}, Shift = 2}}, // 674: 工廠環境の整備\r
+            {675, new QuestSpec {Interval = Quarterly, MaxArray = new[] {6, 4}}}, // 675: 運用装備の統合整備\r
+            {676, new QuestSpec {Interval = Weekly, MaxArray = new[] {3, 3, 1}}}, // 676: 装備開発力の集中整備\r
+\r
+            {702, new QuestPowerup {Interval = Daily, Max = 2}}, // 702: 艦の「近代化改修」を実施せよ!\r
+            {703, new QuestPowerup {Interval = Weekly, Max = 15}} // 703: 「近代化改修」を進め、戦備を整えよ!\r
+        };\r
+        // @formatter:on\r
+\r
+        private readonly Dictionary<int, QuestCount> _countDict = new Dictionary<int, QuestCount>();\r
+\r
+        public QuestCount GetCount(int id)\r
+        {\r
+            if (_countDict.TryGetValue(id, out var value))\r
+                return value;\r
+            if (QuestSpecs.TryGetValue(id, out var spec))\r
+            {\r
+                var nowArray = spec.MaxArray?.Select(x => 0).ToArray();\r
+                return _countDict[id] = new QuestCount\r
+                {\r
+                    Id = id,\r
+                    Now = 0,\r
+                    NowArray = nowArray,\r
+                    Spec = spec\r
+                };\r
+            }\r
+            return new QuestCount {Spec = new QuestSpec {AdjustCount = false}};\r
+        }\r
+\r
+        public void Remove(int id)\r
+        {\r
+            _countDict.Remove(id);\r
+        }\r
+\r
+        public void Remove(QuestInterval interval)\r
+        {\r
+            foreach (var id in\r
+                _countDict.Where(pair => pair.Value.Spec.Interval == interval).Select(pair => pair.Key).ToArray())\r
+            {\r
+                _countDict.Remove(id);\r
+            }\r
+        }\r
+\r
+        public IEnumerable<QuestCount> CountList\r
+        {\r
+            get => _countDict.Values.Where(c => c.Now > 0 || (c.NowArray?.Any(n => n > 0) ?? false));\r
+            set\r
+            {\r
+                if (value == null)\r
+                    return;\r
+                foreach (var count in value)\r
+                {\r
+                    count.Spec = QuestSpecs[count.Id];\r
+                    _countDict[count.Id] = count;\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    public class QuestInfo : IHaveState\r
     {\r
-        private DateTime _lastCreared;\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 _lastReset;\r
 \r
         private readonly Color[] _color =\r
         {\r
@@ -40,16 +294,21 @@ namespace KancolleSniffer
             Color.FromArgb(200, 148, 231), Color.FromArgb(232, 57, 41)\r
         };\r
 \r
-        public int QuestCount { get; set; }\r
+        public int AcceptMax { get; set; } = 5;\r
+\r
+        public QuestStatus[] Quests => _quests.Values.ToArray();\r
+\r
+        public QuestInfo(ItemInfo itemInfo, BattleInfo battleInfo, Func<DateTime> nowFunc = null)\r
+        {\r
+            _itemInfo = itemInfo;\r
+            _battleInfo = battleInfo;\r
+            if (nowFunc != null)\r
+                _nowFunc = nowFunc;\r
+        }\r
 \r
         public void InspectQuestList(dynamic json)\r
         {\r
-            var resetTime = DateTime.Today.AddHours(5);\r
-            if (DateTime.Now >= resetTime && _lastCreared < resetTime)\r
-            {\r
-                _quests.Clear(); // 前日に未消化のデイリーを消す。\r
-                _lastCreared = DateTime.Now;\r
-            }\r
+            ResetQuests();\r
             if (json.api_list == null)\r
                 return;\r
             for (var i = 0; i < 2; i++)\r
@@ -85,17 +344,22 @@ namespace KancolleSniffer
                             progress = 100;\r
                             goto case 2;\r
                         case 2:\r
+                            var count = _countList.GetCount(id);\r
+                            if (count.AdjustCount(progress))\r
+                                NeedSave = true;\r
                             _quests[id] = new QuestStatus\r
                             {\r
+                                Id = id,\r
                                 Category = cat,\r
                                 Name = name,\r
+                                Count = count,\r
                                 Progress = progress,\r
                                 Color = cat <= _color.Length ? _color[cat - 1] : Control.DefaultBackColor\r
                             };\r
                             break;\r
                     }\r
                 }\r
-                if (_quests.Count <= QuestCount)\r
+                if (_quests.Count <= AcceptMax)\r
                     break;\r
                 /*\r
                  * ほかのPCで任務を達成した場合、任務が消えずに受領した任務の数が_questCountを超えることがある。\r
@@ -105,6 +369,230 @@ namespace KancolleSniffer
             }\r
         }\r
 \r
+        private void ResetQuests()\r
+        {\r
+            var now = _nowFunc();\r
+            var daily = now.Date.AddHours(5);\r
+            if (!(_lastReset < daily && daily <= now))\r
+                return;\r
+            _quests.Clear(); // 前日に未消化のデイリーを消す。\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
+                _countList.Remove(QuestInterval.Weekly);\r
+            var monthly = new DateTime(now.Year, now.Month, 1, 5, 0, 0);\r
+            if (_lastReset < monthly && monthly <= now)\r
+                _countList.Remove(QuestInterval.Monthly);\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
+                _countList.Remove(QuestInterval.Quarterly);\r
+            _lastReset = now;\r
+        }\r
+\r
+        private bool _boss;\r
+        private int _map;\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
+            _boss = (int)json.api_event_id == 5;\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.EnemyResultStatus.Concat(_battleInfo.EnemyGuardResultStatus));\r
+                        if (num > 0)\r
+                            AddCount(count, num);\r
+                        break;\r
+                }\r
+            }\r
+            if (_quests.TryGetValue(214, out var ago))\r
+            {\r
+                var array = ago.Count.NowArray;\r
+                if (_boss)\r
+                {\r
+                    array[2]++;\r
+                    if (QuestSortie.CompareRank(rank, "B") <= 0)\r
+                        array[3]++;\r
+                    NeedSave = true;\r
+                }\r
+                if (rank == "S")\r
+                {\r
+                    array[1]++;\r
+                    NeedSave = true;\r
+                }\r
+            }\r
+            if (_quests.TryGetValue(854, out var opz) && _boss)\r
+            {\r
+                var array = opz.Count.NowArray;\r
+                switch (_map)\r
+                {\r
+                    case 24 when QuestSortie.CompareRank(rank, "A") <= 0:\r
+                        array[0]++;\r
+                        NeedSave = true;\r
+                        break;\r
+                    case 61 when QuestSortie.CompareRank(rank, "A") <= 0:\r
+                        array[1]++;\r
+                        NeedSave = true;\r
+                        break;\r
+                    case 63 when QuestSortie.CompareRank(rank, "A") <= 0:\r
+                        array[2]++;\r
+                        NeedSave = true;\r
+                        break;\r
+                    case 64 when QuestSortie.CompareRank(rank, "S") <= 0:\r
+                        array[3]++;\r
+                        NeedSave = true;\r
+                        break;\r
+                }\r
+            }\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
+        }\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
+\r
+        public void InspectMissionResult(string request, dynamic json)\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
+                return;\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(_missionId[deck - 1]))\r
+                    IncrementCount(count);\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
+        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
+\r
+        public void CountCreateShip()\r
+        {\r
+            IncrementCount(606);\r
+            IncrementCount(608);\r
+        }\r
+\r
+        public void InspectDestroyShip(string request)\r
+        {\r
+            AddCount(609, HttpUtility.ParseQueryString(request)["api_ship_id"].Split(',').Length);\r
+        }\r
+\r
+        public void CountRemodelSlot() => IncrementCount(619);\r
+\r
+        public void InspectDestroyItem(string request, dynamic json)\r
+        {\r
+            var values = HttpUtility.ParseQueryString(request);\r
+            var items = values["api_slotitem_ids"].Split(',')\r
+                .Select(id => _itemInfo.GetStatus(int.Parse(id)).Spec.Type).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
+                AddCount(count, items.Count(destroy.Check));\r
+            }\r
+            if (_quests.TryGetValue(675, out var q675))\r
+            {\r
+                q675.Count.NowArray[0] += items.Count(id => id == 6);\r
+                q675.Count.NowArray[1] += items.Count(id => id == 21);\r
+                NeedSave = true;\r
+            }\r
+            if (_quests.TryGetValue(676, out var q676))\r
+            {\r
+                q676.Count.NowArray[0] += items.Count(id => id == 2);\r
+                q676.Count.NowArray[1] += items.Count(id => id == 4);\r
+                q676.Count.NowArray[2] += items.Count(id => id == 30);\r
+                NeedSave = true;\r
+            }\r
+        }\r
+\r
+        public void InspectPowerup(dynamic json)\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
+        }\r
+\r
         public void InspectStop(string request)\r
         {\r
             var values = HttpUtility.ParseQueryString(request);\r
@@ -113,9 +601,27 @@ namespace KancolleSniffer
 \r
         public void InspectClearItemGet(string request)\r
         {\r
-            InspectStop(request);\r
+            var values = HttpUtility.ParseQueryString(request);\r
+            var id = int.Parse(values["api_quest_id"]);\r
+            _countList.Remove(id);\r
+            _quests.Remove(id);\r
+            NeedSave = true;\r
         }\r
 \r
-        public QuestStatus[] Quests => _quests.Values.ToArray();\r
+        public bool NeedSave { get; private set; }\r
+\r
+        public void SaveState(Status status)\r
+        {\r
+            status.QuestLastReset = _lastReset;\r
+            if (_countList == null)\r
+                return;\r
+            status.QuestCountList = _countList.CountList.ToArray();\r
+        }\r
+\r
+        public void LoadState(Status status)\r
+        {\r
+            _countList.CountList = status.QuestCountList;\r
+            _lastReset = status.QuestLastReset;\r
+        }\r
     }\r
 }
\ No newline at end of file
index 2b66b02..6e34e30 100644 (file)
@@ -540,7 +540,7 @@ namespace KancolleSniffer
                 _shipInfo[ship.Id] = ship;\r
             foreach (var entry in ships.Zip(slots, (ship, slot) =>new {ship, slot}))\r
             {\r
-                entry.ship.Slot = _itemInfo.InjectItems(entry.slot.Take(5)).ToArray();\r
+                entry.ship.Slot = _itemInfo.InjectItems(entry.slot.Take(5));\r
                 if (entry.slot.Length >= 6)\r
                     entry.ship.SlotEx = _itemInfo.InjectItems(entry.slot.Skip(5)).First();\r
             }\r
index cc41743..a8d3d99 100644 (file)
@@ -24,7 +24,7 @@ namespace KancolleSniffer
         private bool _start;\r
         private readonly ItemInfo _itemInfo = new ItemInfo();\r
         private readonly MaterialInfo _materialInfo = new MaterialInfo();\r
-        private readonly QuestInfo _questInfo = new QuestInfo();\r
+        private readonly QuestInfo _questInfo;\r
         private readonly MissionInfo _missionInfo = new MissionInfo();\r
         private readonly ShipInfo _shipInfo;\r
         private readonly ConditionTimer _conditionTimer;\r
@@ -76,8 +76,9 @@ namespace KancolleSniffer
             _akashiTimer = new AkashiTimer(_shipInfo, _dockInfo, _presetDeck);\r
             _battleInfo = new BattleInfo(_shipInfo, _itemInfo);\r
             _logger = new Logger(_shipInfo, _itemInfo, _battleInfo);\r
+            _questInfo = new QuestInfo(_itemInfo, _battleInfo);\r
             _baseAirCoprs = new BaseAirCoprs(_itemInfo);\r
-            _haveState = new List<IHaveState> {_achievement, _materialInfo, _conditionTimer, _exMapInfo};\r
+            _haveState = new List<IHaveState> {_achievement, _materialInfo, _conditionTimer, _exMapInfo, _questInfo};\r
         }\r
 \r
         private void SaveState()\r
@@ -145,11 +146,12 @@ namespace KancolleSniffer
             _shipInfo.ClearBadlyDamagedShips();\r
             _conditionTimer.CalcRegenTime();\r
             _missionInfo.InspectDeck(data.api_deck_port);\r
+            _questInfo.InspectDeck(data.api_deck_port);\r
             _dockInfo.InspectNDock(data.api_ndock);\r
             _akashiTimer.Port();\r
             _achievement.InspectBasic(data.api_basic);\r
             if (data.api_parallel_quest_count()) // 昔のログにはないので\r
-                _questInfo.QuestCount = (int)data.api_parallel_quest_count;\r
+                _questInfo.AcceptMax = (int)data.api_parallel_quest_count;\r
             if (data.api_event_object())\r
                 _baseAirCoprs.InspectEventObject(data.api_event_object);\r
             if (data.api_plane_info())\r
@@ -210,6 +212,7 @@ namespace KancolleSniffer
                 _shipInfo.InspectDeck(data);\r
                 _missionInfo.InspectDeck(data);\r
                 _akashiTimer.CheckFleet();\r
+                _questInfo.InspectDeck(data);\r
                 return Update.Mission | Update.Timer;\r
             }\r
             if (url.EndsWith("api_get_member/ship2"))\r
@@ -272,7 +275,8 @@ namespace KancolleSniffer
                 _itemInfo.InspectCreateItem(data);\r
                 _materialInfo.InspectCreateIem(data);\r
                 _logger.InspectCreateItem(request, data);\r
-                return Update.Item;\r
+                _questInfo.CountCreateItem();\r
+                return Update.Item | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kousyou/getship"))\r
             {\r
@@ -289,13 +293,15 @@ namespace KancolleSniffer
                 _materialInfo.InspectDestroyShip(data);\r
                 _conditionTimer.CheckCond();\r
                 _akashiTimer.CheckFleet();\r
-                return Update.Item | Update.Ship;\r
+                _questInfo.InspectDestroyShip(request);\r
+                return Update.Item | Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kousyou/destroyitem2"))\r
             {\r
+                _questInfo.InspectDestroyItem(request, data); // 本当に削除される前\r
                 _itemInfo.InspectDestroyItem(request, data);\r
                 _materialInfo.InspectDestroyItem(data);\r
-                return Update.Item;\r
+                return Update.Item | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kousyou/remodel_slot"))\r
             {\r
@@ -303,12 +309,14 @@ namespace KancolleSniffer
                 _logger.InspectRemodelSlot(request, data); // 資材の差が必要なので_materialInfoより前\r
                 _itemInfo.InspectRemodelSlot(data);\r
                 _materialInfo.InspectRemodelSlot(data);\r
-                return Update.Item;\r
+                _questInfo.CountRemodelSlot();\r
+                return Update.Item | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kousyou/createship"))\r
             {\r
                 _logger.InspectCreateShip(request);\r
-                return Update.None;\r
+                _questInfo.CountCreateShip();\r
+                return Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kousyou/createship_speedchange"))\r
             {\r
@@ -343,12 +351,14 @@ namespace KancolleSniffer
                 _battleInfo.InspectBattleResult(data);\r
                 _exMapInfo.InspectBattleResult(data);\r
                 _logger.InspectBattleResult(data);\r
-                return Update.Ship;\r
+                _questInfo.InspectBattleResult(data);\r
+                return Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_practice/battle_result"))\r
             {\r
                 _battleInfo.InspectPracticeResult(data);\r
-                return Update.Ship;\r
+                _questInfo.InspectPracticeResult(data);\r
+                return Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("/goback_port"))\r
             {\r
@@ -416,14 +426,16 @@ namespace KancolleSniffer
             {\r
                 _shipInfo.InspectCharge(data);\r
                 _materialInfo.InspectCharge(data);\r
-                return Update.Item | Update.Ship;\r
+                _questInfo.CountCharge();\r
+                return Update.Item | Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kaisou/powerup"))\r
             {\r
                 _shipInfo.InspectPowerup(request, data);\r
                 _conditionTimer.CheckCond();\r
                 _akashiTimer.CheckFleet();\r
-                return Update.Item | Update.Ship;\r
+                _questInfo.InspectPowerup(data);\r
+                return Update.Item | Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_kaisou/slot_exchange_index"))\r
             {\r
@@ -440,10 +452,11 @@ namespace KancolleSniffer
                 _dockInfo.InspectNyukyo(request);\r
                 _conditionTimer.CheckCond();\r
                 _akashiTimer.CheckFleet();\r
+                _questInfo.CountNyukyo();\r
                 var ndock = HttpUtility.ParseQueryString(request)["api_ndock_id"];\r
                 if (ndock != null && int.TryParse(ndock, out int id))\r
                     RepeatingTimerController?.Stop("入渠終了", id - 1);\r
-                return Update.Item | Update.Ship;\r
+                return Update.Item | Update.Ship | Update.QuestList;\r
             }\r
             if (url.EndsWith("api_req_nyukyo/speedchange"))\r
             {\r
@@ -459,6 +472,7 @@ namespace KancolleSniffer
                 _battleInfo.InspectMapStart(data);\r
                 _logger.InspectMapStart(data);\r
                 _miscTextInfo.ClearFlag = true;\r
+                _questInfo.InspectMapStart(data);\r
                 RepeatingTimerController?.Suspend();\r
                 return Update.Timer | Update.Ship;\r
             }\r
@@ -467,6 +481,7 @@ namespace KancolleSniffer
                 _exMapInfo.InspectMapNext(data);\r
                 _battleInfo.InspectMapNext(data);\r
                 _logger.InspectMapNext(data);\r
+                _questInfo.InspectMapNext(data);\r
                 return Update.None;\r
             }\r
             if (url.EndsWith("api_req_mission/start"))\r
@@ -480,6 +495,7 @@ namespace KancolleSniffer
             {\r
                 _materialInfo.InspectMissionResult(data);\r
                 _logger.InspectMissionResult(data);\r
+                _questInfo.InspectMissionResult(request, data);\r
                 return Update.Item;\r
             }\r
             if (url.EndsWith("api_req_quest/stop"))\r
index 5e4e4ad..f3fa4b8 100644 (file)
@@ -35,6 +35,9 @@ namespace KancolleSniffer
         public List<MaterialCount> MaterialHistory { get; set; }\r
         public double CondRegenTime { get; set; }\r
         public ExMapInfo.ExMapState ExMapState { get; set; }\r
+        public QuestCount[] QuestCountList { get; set; }\r
+        public DateTime QuestLastReset { get; set; }\r
+\r
 \r
         public Status()\r
         {\r