OSDN Git Service

明石タイマーを実装する
authorKazuhiro Fujieda <fujieda@users.sourceforge.jp>
Wed, 21 May 2014 12:55:10 +0000 (21:55 +0900)
committerKazuhiro Fujieda <fujieda@users.sourceforge.jp>
Fri, 23 May 2014 13:22:16 +0000 (22:22 +0900)
KancolleSniffer/AkashiTimer.cs [new file with mode: 0644]
KancolleSniffer/DockInfo.cs
KancolleSniffer/ItemInfo.cs
KancolleSniffer/KancolleSniffer.csproj
KancolleSniffer/MainForm.Designer.cs
KancolleSniffer/MainForm.cs
KancolleSniffer/MainForm.resx
KancolleSniffer/MissionInfo.cs
KancolleSniffer/ShipInfo.cs
KancolleSniffer/Sniffer.cs

diff --git a/KancolleSniffer/AkashiTimer.cs b/KancolleSniffer/AkashiTimer.cs
new file mode 100644 (file)
index 0000000..8f894df
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright (C) 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+using System;\r
+using System.Linq;\r
+\r
+namespace KancolleSniffer\r
+{\r
+    public class AkashiTimer\r
+    {\r
+        private readonly ShipInfo _shipInfo;\r
+        private readonly ItemInfo _itemInfo;\r
+        private readonly DockInfo _dockInfo;\r
+        private readonly MissionInfo _missionInfo;\r
+        private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
+\r
+        private struct RepairStatus\r
+        {\r
+            public DateTime Timer { get; set; }\r
+            public int TotalHp { get; set; }\r
+            public int[] Deck { private get; set; }\r
+\r
+            public void Invalidate()\r
+            {\r
+                Timer = DateTime.MinValue;\r
+                TotalHp = 0;\r
+                Deck = null;\r
+            }\r
+\r
+            public bool DeckChanged(int[] deck)\r
+            {\r
+                return Deck != null && Deck.Where((t, i) => deck[i] != t).Any();\r
+            }\r
+        }\r
+\r
+        public AkashiTimer(ShipInfo ship, ItemInfo item, DockInfo dock, MissionInfo mission)\r
+        {\r
+            _shipInfo = ship;\r
+            _itemInfo = item;\r
+            _dockInfo = dock;\r
+            _missionInfo = mission;\r
+        }\r
+\r
+        public void SetTimer(bool port = false)\r
+        {\r
+            for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
+                SetTimer(fleet, port);\r
+        }\r
+\r
+        private void SetTimer(int fleet, bool port)\r
+        {\r
+            var deck = _shipInfo.GetDeck(fleet);\r
+            var fs = deck[0];\r
+            if (fs == -1 || !_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) ||\r
+                _missionInfo.InMission(fleet))\r
+            {\r
+                InvalidateTimer(fleet);\r
+                return;\r
+            }\r
+            if (_repairStatuses[fleet].DeckChanged(deck))\r
+                InvalidateTimer(fleet);\r
+            var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\r
+            var targets = deck.Take(cap).Where(id => id != -1 && !_dockInfo.InNDock(id)).ToArray();\r
+            var totalHp = (from id in targets\r
+                let status = _shipInfo[id]\r
+                where status.NowHp < status.MaxHp && status.DamageLevel < 2\r
+                select status.NowHp).Sum();\r
+            if (totalHp == 0)\r
+            {\r
+                InvalidateTimer(fleet);\r
+                return;\r
+            }\r
+            var r = _repairStatuses[fleet];\r
+            if (r.TotalHp == totalHp)\r
+                return;\r
+            var timer = r.Timer;\r
+            /*\r
+             * 母港に遷移したときに、耐久値が回復しているか修理開始から20分経過しているときに\r
+             * タイマーをリスタートする。\r
+             * \r
+             * Q. なぜ20分でリスタートするのか?\r
+             * \r
+             * A. 明石の修理は戦闘中も続くので、戦闘中に修理開始から20分経つと母港に戻った\r
+             *    ときに耐久値が回復する。最後の戦闘で損傷すると、損傷と回復が同時に耐久値に\r
+             *    反映されて回復が起こったことがわからない。耐久値の回復だけを基準にすると\r
+             *    リスタートできないので、20分経過していたらリスタートする。\r
+            */\r
+            if (timer == DateTime.MinValue ||\r
+                (port && (totalHp > r.TotalHp || (DateTime.Now - timer).TotalMinutes > 20)))\r
+                timer = DateTime.Now;\r
+            _repairStatuses[fleet] = new RepairStatus\r
+            {\r
+                Timer = timer,\r
+                TotalHp = totalHp,\r
+                Deck = deck.ToArray()\r
+            };\r
+        }\r
+\r
+        private void InvalidateTimer(int fleet)\r
+        {\r
+            _repairStatuses[fleet].Invalidate();\r
+        }\r
+\r
+        public DateTime this[int fleet]\r
+        {\r
+            get { return _repairStatuses[fleet].Timer; }\r
+        }\r
+    }\r
+}
\ No newline at end of file
index d2852d5..7a4f1d6 100644 (file)
@@ -55,6 +55,11 @@ namespace KancolleSniffer
             }\r
         }\r
 \r
+        public bool InNDock(int id)\r
+        {\r
+            return _ndoc.Any(n => n == id);\r
+        }\r
+\r
         public void InspectKDock(dynamic json)\r
         {\r
             foreach (var entry in json)\r
index abced8d..7c99d9b 100644 (file)
@@ -20,10 +20,16 @@ using System.Web;
 \r
 namespace KancolleSniffer\r
 {\r
+    public struct ItemSpec\r
+    {\r
+        public string Name;\r
+        public int TyKu;\r
+    }\r
+\r
     public class ItemInfo\r
     {\r
         private int _nowShips;\r
-        private readonly Dictionary<int,int> _itemSpecs = new Dictionary<int, int>();\r
+        private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();\r
         private readonly Dictionary<int, int> _itemIds = new Dictionary<int, int>();\r
 \r
         public int MaxShips { get; private set; }\r
@@ -77,8 +83,11 @@ namespace KancolleSniffer
         {\r
             foreach (var entry in json)\r
             {\r
-                if ((int)entry.api_type[0] == 3) // 艦載機\r
-                    _itemSpecs[(int)entry.api_id] = (int)entry.api_tyku;                \r
+                _itemSpecs[(int)entry.api_id] = new ItemSpec\r
+                {\r
+                    Name = (string)entry.api_name,\r
+                    TyKu = (int)entry.api_type[0] == 3 ? (int)entry.api_tyku : 0 // 艦載機のみ\r
+                };\r
             }\r
         }\r
 \r
@@ -113,12 +122,16 @@ namespace KancolleSniffer
             NowItems -= values["api_slotitem_ids"].Split(',').Length;\r
         }\r
 \r
-        public int GetTyKu(int id)\r
+        public ItemSpec this[int id]\r
         {\r
-            int item;\r
-            int tyku;\r
-            return _itemIds.TryGetValue(id, out item) ? _itemSpecs.TryGetValue(item, out tyku) ? tyku : 0 : 0;\r
+            get\r
+            {\r
+                int itemId;\r
+                ItemSpec spec;\r
+                if (_itemIds.TryGetValue(id, out itemId) && _itemSpecs.TryGetValue(itemId, out spec))\r
+                    return spec;\r
+                return new ItemSpec();\r
+            }\r
         }\r
-\r
     }\r
 }
\ No newline at end of file
index 39a700b..9b0dddd 100644 (file)
@@ -56,6 +56,7 @@
     <Reference Include="System.Windows.Forms" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="AkashiTimer.cs" />\r
     <Compile Include="Config.cs" />\r
     <Compile Include="ConfigDialog.cs">\r
       <SubType>Form</SubType>\r
index 7786369..11c2b5d 100644 (file)
@@ -48,6 +48,7 @@ namespace KancolleSniffer
             this.components = new System.ComponentModel.Container();\r
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));\r
             this.panelHeadquarters = new System.Windows.Forms.Panel();\r
+            this.labelLogin = new System.Windows.Forms.Label();\r
             this.labelNumOfBuckets = new System.Windows.Forms.Label();\r
             this.label3 = new System.Windows.Forms.Label();\r
             this.labelNumOfEquips = new System.Windows.Forms.Label();\r
@@ -55,6 +56,7 @@ namespace KancolleSniffer
             this.labelNumOfShips = new System.Windows.Forms.Label();\r
             this.label1 = new System.Windows.Forms.Label();\r
             this.panelFleet1 = new System.Windows.Forms.Panel();\r
+            this.labelAkashiTimer = new System.Windows.Forms.Label();\r
             this.labelAirSuperiority = new System.Windows.Forms.Label();\r
             this.label27 = new System.Windows.Forms.Label();\r
             this.label21 = new System.Windows.Forms.Label();\r
@@ -174,7 +176,6 @@ namespace KancolleSniffer
             this.labelFleet3 = new System.Windows.Forms.Label();\r
             this.labelCheckFleet2 = new System.Windows.Forms.Label();\r
             this.labelFleet2 = new System.Windows.Forms.Label();\r
-            this.labelLogin = new System.Windows.Forms.Label();\r
             this.panelHeadquarters.SuspendLayout();\r
             this.panelFleet1.SuspendLayout();\r
             this.panelDock.SuspendLayout();\r
@@ -200,6 +201,16 @@ namespace KancolleSniffer
             this.panelHeadquarters.Size = new System.Drawing.Size(263, 35);\r
             this.panelHeadquarters.TabIndex = 0;\r
             // \r
+            // labelLogin\r
+            // \r
+            this.labelLogin.AutoSize = true;\r
+            this.labelLogin.Font = new System.Drawing.Font("MS UI Gothic", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));\r
+            this.labelLogin.Location = new System.Drawing.Point(6, 4);\r
+            this.labelLogin.Name = "labelLogin";\r
+            this.labelLogin.Size = new System.Drawing.Size(203, 26);\r
+            this.labelLogin.TabIndex = 23;\r
+            this.labelLogin.Text = "艦これにログインしてください。\r\nログイン中ならログインし直してください。";\r
+            // \r
             // labelNumOfBuckets\r
             // \r
             this.labelNumOfBuckets.Location = new System.Drawing.Point(120, 19);\r
@@ -257,6 +268,7 @@ namespace KancolleSniffer
             // panelFleet1\r
             // \r
             this.panelFleet1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\r
+            this.panelFleet1.Controls.Add(this.labelAkashiTimer);\r
             this.panelFleet1.Controls.Add(this.labelAirSuperiority);\r
             this.panelFleet1.Controls.Add(this.label27);\r
             this.panelFleet1.Controls.Add(this.label21);\r
@@ -304,6 +316,16 @@ namespace KancolleSniffer
             this.panelFleet1.Size = new System.Drawing.Size(259, 134);\r
             this.panelFleet1.TabIndex = 2;\r
             // \r
+            // labelAkashiTimer\r
+            // \r
+            this.labelAkashiTimer.Location = new System.Drawing.Point(49, 20);\r
+            this.labelAkashiTimer.Name = "labelAkashiTimer";\r
+            this.labelAkashiTimer.Size = new System.Drawing.Size(45, 12);\r
+            this.labelAkashiTimer.TabIndex = 23;\r
+            this.labelAkashiTimer.Text = "00:00:00";\r
+            this.labelAkashiTimer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;\r
+            this.labelAkashiTimer.Visible = false;\r
+            // \r
             // labelAirSuperiority\r
             // \r
             this.labelAirSuperiority.Location = new System.Drawing.Point(43, 117);\r
@@ -1386,16 +1408,6 @@ namespace KancolleSniffer
             this.labelFleet2.Text = "第二艦隊";\r
             this.labelFleet2.Click += new System.EventHandler(this.labelFleet_Click);\r
             // \r
-            // labelLogin\r
-            // \r
-            this.labelLogin.AutoSize = true;\r
-            this.labelLogin.Font = new System.Drawing.Font("MS UI Gothic", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));\r
-            this.labelLogin.Location = new System.Drawing.Point(6, 4);\r
-            this.labelLogin.Name = "labelLogin";\r
-            this.labelLogin.Size = new System.Drawing.Size(203, 26);\r
-            this.labelLogin.TabIndex = 23;\r
-            this.labelLogin.Text = "艦これにログインしてください。\r\nログイン中ならログインし直してください。";\r
-            // \r
             // MainForm\r
             // \r
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);\r
@@ -1578,6 +1590,7 @@ namespace KancolleSniffer
         private System.Windows.Forms.Label labelAirSuperiority;\r
         private System.Windows.Forms.Label label27;\r
         private System.Windows.Forms.Label labelLogin;\r
+        private System.Windows.Forms.Label labelAkashiTimer;\r
     }\r
 }\r
 \r
index 98693cc..c99f02d 100644 (file)
@@ -62,7 +62,7 @@ namespace KancolleSniffer
             var update = (Sniffer.Update)_sniffer.Sniff(oSession.url, request, json);\r
             if (update == Sniffer.Update.Start)\r
             {\r
-                Invoke(new Action(() => {labelLogin.Visible = false;}));\r
+                Invoke(new Action(() => { labelLogin.Visible = false; }));\r
                 _started = true;\r
                 return;\r
             }\r
@@ -180,8 +180,8 @@ namespace KancolleSniffer
                 var stat = statuses[i];\r
                 name[i].Text = stat.Name;\r
                 lv[i].Text = stat.Level.ToString("D");\r
-                SetHpLavel(hp[i], stat.NowHp, stat.MaxHp);\r
-                if (stat.Name == null)\r
+                SetHpLavel(hp[i], stat);\r
+                if (stat.MaxHp == 0)\r
                 {\r
                     cond[i].Text = "0";\r
                     cond[i].BackColor = DefaultBackColor;\r
@@ -192,6 +192,8 @@ namespace KancolleSniffer
             }\r
             labelAirSuperiority.Text = _sniffer.GetAirSuperiority(_currentFleet).ToString("D");\r
             UpdateChargeInfo();\r
+            UpdateCondTimers();\r
+            UpdateAkashiTimer();\r
         }\r
 \r
         private void UpdateChargeInfo()\r
@@ -207,13 +209,11 @@ namespace KancolleSniffer
             }\r
         }\r
 \r
-        private void SetHpLavel(Label label, int now, int max)\r
+        private void SetHpLavel(Label label, ShipStatus status)\r
         {\r
-            label.Text = string.Format("{0:D}/{1:D}", now, max);\r
-            var damage = max == 0 ? 1 : (double)now / max;\r
-            label.BackColor = damage > 0.75\r
-                ? DefaultBackColor\r
-                : damage > 0.5 ? Color.FromArgb(255, 240, 240, 100) : damage > 0.25 ? Color.Orange : Color.Red;\r
+            var colors = new[] {DefaultBackColor, Color.FromArgb(255, 240, 240, 100), Color.Orange, Color.Red};\r
+            label.Text = string.Format("{0:D}/{1:D}", status.NowHp, status.MaxHp);\r
+            label.BackColor = colors[status.DamageLevel];\r
         }\r
 \r
         private void SetCondLabel(Label label, int cond)\r
@@ -262,6 +262,7 @@ namespace KancolleSniffer
                 timer.NeedRing = false;\r
             }\r
             UpdateCondTimers();\r
+            UpdateAkashiTimer();\r
         }\r
 \r
         private void SetTimerLabel(Label label, RingTimer timer)\r
@@ -279,6 +280,24 @@ namespace KancolleSniffer
                 entry.label.Text = entry.time > now ? (entry.time - now).ToString(@"mm\:ss") : "00:00";\r
         }\r
 \r
+        private void UpdateAkashiTimer()\r
+        {\r
+            if (!_sniffer.GetShipStatuses(_currentFleet)[0].Name.StartsWith("明石"))\r
+            {\r
+                labelAkashiTimer.Visible = false;\r
+                return;\r
+            }\r
+            labelAkashiTimer.Visible = true;\r
+            var start = _sniffer.GetAkashiStartTime(_currentFleet);\r
+            if (start == DateTime.MinValue)\r
+            {\r
+                labelAkashiTimer.Text = "00:00:00";\r
+                return;\r
+            }\r
+            var span = DateTime.Now - start;\r
+            labelAkashiTimer.Text = span.Days == 0 ? span.ToString(@"hh\:mm\:ss") : span.ToString(@"d\.hh\:mm");\r
+        }\r
+\r
         private void UpdateQuestList()\r
         {\r
             var name = new[] {labelQuest1, labelQuest2, labelQuest3, labelQuest4, labelQuest5};\r
@@ -329,7 +348,6 @@ namespace KancolleSniffer
             if (!_started)\r
                 return;\r
             UpdateShipInfo();\r
-            UpdateCondTimers();\r
         }\r
     }\r
 }
\ No newline at end of file
index 649b99e..ed7585a 100644 (file)
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA+\r
-        CwAAAk1TRnQBSQFMAgEBBQEAAXABAAFwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
+        CwAAAk1TRnQBSQFMAgEBBQEAAYABAAGAAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
         AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA\r
         AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5\r
         AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA\r
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABu\r
-        CwAAAk1TRnQBSQFMAgEBBQEAAXABAAFwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
+        CwAAAk1TRnQBSQFMAgEBBQEAAYABAAGAAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
         AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA\r
         AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5\r
         AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA\r
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABm\r
-        BwAAAk1TRnQBSQFMAwEBAAEoAQABKAEAAQcBAAEPAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA\r
+        BwAAAk1TRnQBSQFMAwEBAAE4AQABOAEAAQcBAAEPAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA\r
         ARwDAAEPAwABAQEAAQgFAAGkAQEYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA\r
         AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5\r
         AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA\r
index 4ba0f6a..5fdf967 100644 (file)
@@ -61,5 +61,12 @@ namespace KancolleSniffer
         {\r
             get { return _missions; }\r
         }\r
+\r
+        public bool InMission(int fleet)\r
+        {\r
+            if (fleet == 0)\r
+                return false;\r
+            return _missions[fleet - 1].Name != "";\r
+        }\r
     }\r
 }
\ No newline at end of file
index 376585f..c1931a2 100644 (file)
@@ -35,6 +35,15 @@ namespace KancolleSniffer
         public int Bull { get; set; }\r
         public int[] OnSlot { get; set; }\r
         public int[] Slot { get; set; }\r
+\r
+        public int DamageLevel\r
+        {\r
+            get\r
+            {\r
+                var ratio = MaxHp == 0 ? 1 : (double)NowHp / MaxHp;\r
+                return ratio > 0.75 ? 0 : ratio > 0.5 ? 1 : ratio > 0.25 ? 2 : 3;\r
+            }\r
+        }\r
     }\r
 \r
     public struct ChargeStatus\r
@@ -45,9 +54,18 @@ namespace KancolleSniffer
 \r
     public class ShipInfo\r
     {\r
-        private readonly int[][] _decks = new int[4][];\r
+        public const int FleetCount = 4;\r
+        public const int MemberCount = 6;\r
+\r
+        private readonly int[][] _decks = new int[FleetCount][];\r
         private readonly Dictionary<int, ShipStatus> _shipInfo = new Dictionary<int, ShipStatus>();\r
-        private readonly DateTime[][] _recoveryTimes = {new DateTime[3], new DateTime[3], new DateTime[3], new DateTime[3]};\r
+\r
+        private readonly DateTime[][] _recoveryTimes =\r
+        {\r
+            new DateTime[3], new DateTime[3], new DateTime[3],\r
+            new DateTime[3]\r
+        };\r
+\r
         private readonly ShipMaster _shipMaster;\r
         private readonly ItemInfo _itemInfo;\r
 \r
@@ -56,8 +74,13 @@ namespace KancolleSniffer
             _shipMaster = shipMaster;\r
             _itemInfo = itemInfo;\r
 \r
-            for (var i = 0; i < _decks.Length; i++)\r
-                _decks[i] = new[] {-1, -1, -1, -1, -1, -1};\r
+            for (var fleet = 0; fleet < FleetCount; fleet++)\r
+            {\r
+                var deck = new int[MemberCount];\r
+                for (var i = 0; i < deck.Length; i++)\r
+                    deck[i] = -1;\r
+                _decks[fleet] = deck;\r
+            }\r
         }\r
 \r
         public DateTime[] GetRecoveryTimes(int fleet)\r
@@ -95,8 +118,8 @@ namespace KancolleSniffer
         {\r
             foreach (var entry in json)\r
             {\r
-                var fleet = (int)entry.api_id;\r
-                var deck = _decks[fleet - 1];\r
+                var fleet = (int)entry.api_id - 1;\r
+                var deck = _decks[fleet];\r
                 for (var i = 0; i < deck.Length; i++)\r
                     deck[i] = (int)entry.api_ship[i];\r
             }\r
@@ -104,8 +127,6 @@ namespace KancolleSniffer
 \r
         private void InspectShipData(dynamic json)\r
         {\r
-            if (!json.IsArray)\r
-                json = new[] {json};\r
             foreach (var entry in json)\r
             {\r
                 _shipInfo[(int)entry.api_id] = new ShipStatus\r
@@ -203,6 +224,11 @@ namespace KancolleSniffer
             }\r
         }\r
 \r
+        private int SlotItemCount(int id)\r
+        {\r
+            return _shipInfo[id].Slot.Count(item => item != -1);\r
+        }\r
+\r
         public void InspectNyukyo(string request)\r
         {\r
             var values = HttpUtility.ParseQueryString(request);\r
@@ -216,18 +242,13 @@ namespace KancolleSniffer
             _itemInfo.NumBuckets--;\r
         }\r
 \r
-        private int SlotItemCount(int id)\r
-        {\r
-            return _shipInfo[id].Slot.Count(item => item != -1);\r
-        }\r
-\r
         private void SetRecoveryTime()\r
         {\r
             for (var fleet = 0; fleet < 4; fleet++)\r
             {\r
                 var cond =\r
-                    (from id in _decks[fleet] where _shipInfo.ContainsKey(id) select _shipInfo[id].Cond).DefaultIfEmpty(49)\r
-                        .Min();\r
+                    (from id in _decks[fleet] where _shipInfo.ContainsKey(id) select _shipInfo[id].Cond)\r
+                        .DefaultIfEmpty(49).Min();\r
                 if (cond < 49 && _recoveryTimes[fleet][2] != DateTime.MinValue) // 計時中\r
                 {\r
                     // コンディション値から推定される残り時刻と経過時間の差\r
@@ -245,7 +266,12 @@ namespace KancolleSniffer
 \r
         public ShipStatus[] GetShipStatuses(int fleet)\r
         {\r
-            return _decks[fleet].Select(id => (id == -1) ? new ShipStatus() : _shipInfo[id]).ToArray();\r
+            return _decks[fleet].Select(id => (id == -1) ? new ShipStatus {Name = ""} : _shipInfo[id]).ToArray();\r
+        }\r
+\r
+        public int[] GetDeck(int fleet)\r
+        {\r
+            return _decks[fleet];\r
         }\r
 \r
         public ShipStatus this[int idx]\r
@@ -264,7 +290,7 @@ namespace KancolleSniffer
                         let spec = _shipMaster[status.ShipId]\r
                         select new {status.Bull, status.Fuel, spec.BullMax, spec.FuelMax})\r
                         .Aggregate(\r
-                            new ChargeStatus(), (result, next) => new ChargeStatus()\r
+                            new ChargeStatus(), (result, next) => new ChargeStatus\r
                             {\r
                                 Bull = Math.Max(result.Bull, CalcChargeState(next.Bull, next.BullMax)),\r
                                 Fuel = Math.Max(result.Fuel, CalcChargeState(next.Fuel, next.FuelMax))\r
@@ -290,9 +316,9 @@ namespace KancolleSniffer
         {\r
             return (from id in _decks[fleet]\r
                 where _shipInfo.ContainsKey(id)\r
-                    let ship = _shipInfo[id]\r
+                let ship = _shipInfo[id]\r
                 from slot in ship.Slot.Zip(ship.OnSlot, (s, o) => new {slot = s, onslot = o})\r
-                select (int)Math.Floor(_itemInfo.GetTyKu(slot.slot) * Math.Sqrt(slot.onslot))).Sum();\r
+                select (int)Math.Floor(_itemInfo[slot.slot].TyKu * Math.Sqrt(slot.onslot))).Sum();\r
         }\r
     }\r
 }
\ No newline at end of file
index c545af1..9cb2a07 100644 (file)
@@ -28,6 +28,7 @@ namespace KancolleSniffer
         private readonly MissionInfo _missionInfo = new MissionInfo();\r
         private readonly ShipInfo _shipInfo;\r
         private readonly DockInfo _dockInfo;\r
+        private readonly AkashiTimer _akashiTimer;\r
 \r
         [Flags]\r
         public enum Update\r
@@ -47,6 +48,7 @@ namespace KancolleSniffer
         {\r
             _shipInfo = new ShipInfo(_shipMaster, _itemInfo);\r
             _dockInfo = new DockInfo(_shipInfo);\r
+            _akashiTimer = new AkashiTimer(_shipInfo, _itemInfo, _dockInfo, _missionInfo);\r
         }\r
 \r
         public Update Sniff(string url, string request, dynamic json)\r
@@ -70,6 +72,7 @@ namespace KancolleSniffer
                 _shipInfo.InspectShip(data);\r
                 _missionInfo.InspectDeck(data.api_deck_port);\r
                 _dockInfo.InspectNDock(data.api_ndock);\r
+                _akashiTimer.SetTimer(true);\r
                 return Update.All;\r
             }\r
             if (url.EndsWith("api_get_member/basic"))\r
@@ -90,11 +93,13 @@ namespace KancolleSniffer
             if (url.EndsWith("api_get_member/ndock"))\r
             {\r
                 _dockInfo.InspectNDock(data);\r
+                _akashiTimer.SetTimer();\r
                 return Update.NDock | Update.Timer;\r
             }\r
             if (url.EndsWith("api_req_hensei/change"))\r
             {\r
                 _shipInfo.InspectChange(request);\r
+                _akashiTimer.SetTimer();\r
                 return Update.Ship;\r
             }\r
             if (url.EndsWith("api_get_member/questlist"))\r
@@ -105,17 +110,20 @@ namespace KancolleSniffer
             if (url.EndsWith("api_get_member/deck"))\r
             {\r
                 _missionInfo.InspectDeck(data);\r
+                _akashiTimer.SetTimer();\r
                 return Update.Mission | Update.Timer;\r
             }\r
             if (url.EndsWith("api_get_member/ship2"))\r
             {\r
                 // ここだけjsonなので注意\r
                 _shipInfo.InspectShip(json);\r
-                return Update.Ship | Update.Item;\r
+                _akashiTimer.SetTimer();\r
+                return Update.Ship;\r
             }\r
             if (url.EndsWith("api_get_member/ship3"))\r
             {\r
                 _shipInfo.InspectShip(data);\r
+                _akashiTimer.SetTimer();\r
                 return Update.Ship;\r
             }\r
             if (url.EndsWith("api_req_hokyu/charge"))\r
@@ -138,6 +146,7 @@ namespace KancolleSniffer
             if (url.EndsWith("api_req_kousyou/destroyship"))\r
             {\r
                 _shipInfo.InspectDestroyShip(request);\r
+                _akashiTimer.SetTimer();\r
                 return Update.Item | Update.Ship;\r
             }\r
             if (url.EndsWith("api_req_kousyou/destroyitem2"))\r
@@ -202,6 +211,11 @@ namespace KancolleSniffer
         {\r
             return _shipInfo.GetAirSuperiority(fleet);\r
         }\r
+\r
+        public DateTime GetAkashiStartTime(int fleet)\r
+        {\r
+            return _akashiTimer[fleet];\r
+        }\r
     }\r
 \r
     public class NameAndTimer\r