OSDN Git Service

複数艦隊で泊地修理を行う際のタイマーを共通化する
authorKazuhiro Fujieda <fujieda@users.sourceforge.jp>
Wed, 14 Jan 2015 14:25:44 +0000 (23:25 +0900)
committerKazuhiro Fujieda <fujieda@users.sourceforge.jp>
Sat, 17 Jan 2015 11:21:12 +0000 (20:21 +0900)
KancolleSniffer/AkashiTimer.cs
KancolleSniffer/MainForm.cs
KancolleSniffer/ShipInfo.cs

index d2caee2..4ee4fd6 100644 (file)
@@ -16,6 +16,7 @@
 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
 \r
 using System;\r
+using System.Collections.Generic;\r
 using System.Linq;\r
 \r
 namespace KancolleSniffer\r
@@ -26,18 +27,8 @@ namespace KancolleSniffer
         private readonly ItemInfo _itemInfo;\r
         private readonly DockInfo _dockInfo;\r
         private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
-\r
-        public class RepairTime\r
-        {\r
-            public int Diff { get; set; }\r
-            public DateTime Time { get; set; }\r
-\r
-            public RepairTime(int diff, DateTime time)\r
-            {\r
-                Diff = diff;\r
-                Time = time;\r
-            }\r
-        }\r
+        private DateTime _start;\r
+        private DateTime _prev;\r
 \r
         public class RepairSpan\r
         {\r
@@ -49,84 +40,71 @@ namespace KancolleSniffer
                 Diff = diff;\r
                 Span = span;\r
             }\r
-\r
-            public RepairSpan(RepairTime time)\r
-            {\r
-                Diff = time.Diff;\r
-                Span = TimeSpan.FromSeconds(Math.Ceiling((time.Time - DateTime.Now).TotalSeconds));\r
-            }\r
         }\r
 \r
         private class RepairStatus\r
         {\r
-            private ShipStatus[] _target;\r
-            private RepairTime[][] _times = new RepairTime[0][];\r
-            private DateTime _prev;\r
-            public DateTime Start { get; set; }\r
-            public int[] Deck { private get; set; }\r
+            private ShipStatus[] _target = new ShipStatus[0];\r
+            private RepairSpan[][] _spans = new RepairSpan[0][];\r
+            private int[] _deck = new int[0];\r
 \r
-            public int TotalHp\r
+            public int[] Deck\r
             {\r
-                get { return _target == null ? 0 : _target.Sum(s => s.NowHp); }\r
+                set { _deck = value; }\r
             }\r
 \r
             public void Invalidate()\r
             {\r
-                Start = DateTime.MinValue;\r
-                Deck = null;\r
-                _target = null;\r
-                _times = new RepairTime[0][];\r
+                _target = new ShipStatus[0];\r
+                _spans = new RepairSpan[0][];\r
+            }\r
+\r
+            public int TotalHp\r
+            {\r
+                get { return _target.Sum(s => s.NowHp); }\r
             }\r
 \r
-            public bool DeckChanged(int[] deck)\r
+            public bool DeckChanged(IEnumerable<int> deck)\r
             {\r
-                return Deck != null && Deck.Where((t, i) => deck[i] != t).Any();\r
+                return !_deck.SequenceEqual(deck);\r
             }\r
 \r
             public void UpdateTarget(ShipStatus[] target)\r
             {\r
                 _target = target;\r
-                UpdateTimes();\r
+                CalcRepairSpan();\r
             }\r
 \r
-            private void UpdateTimes()\r
+            private void CalcRepairSpan()\r
             {\r
-                _times = (from s in _target\r
+                _spans = (from s in _target\r
                     let damage = s.MaxHp - s.NowHp\r
-                    let first = new RepairTime(0, Start.AddMinutes(20))\r
+                    let first = new RepairSpan(0, TimeSpan.FromMinutes(20))\r
                     select damage == 0\r
                         ? null\r
                         : new[] {first}.Concat(from d in Enumerable.Range(2, damage < 2 ? 0 : damage - 1)\r
-                            let span = s.CalcRepairTime(d) + TimeSpan.FromSeconds(30)\r
-                            where span.TotalSeconds > 20 * 60\r
-                            select new RepairTime(d - 1, Start + span)).ToArray()).ToArray();\r
+                            let sec = s.CalcRepairSec(d) + 60\r
+                            where sec > 20 * 60\r
+                            select new RepairSpan(d - 1, TimeSpan.FromSeconds(sec))).ToArray()).ToArray();\r
             }\r
 \r
-            public RepairSpan[] GetTimers()\r
+            public RepairSpan[] GetTimers(DateTime start, DateTime now)\r
             {\r
-                return (from times in _times\r
-                    select times == null\r
+                var span = TimeSpan.FromSeconds((int)(now - start).TotalSeconds);\r
+                return (from spans in _spans\r
+                    select spans == null\r
                         ? new RepairSpan(0, TimeSpan.MinValue)\r
-                        : (from t in times select new RepairSpan(t)).FirstOrDefault(s => s.Span > TimeSpan.Zero)\r
-                          ?? new RepairSpan(times.Last().Diff + 1, TimeSpan.Zero)\r
+                        : (from s in spans select new RepairSpan(s.Diff, s.Span - span))\r
+                            .FirstOrDefault(s => s.Span > TimeSpan.Zero)\r
+                          ?? new RepairSpan(spans.Last().Diff + 1, TimeSpan.Zero)\r
                     ).ToArray();\r
             }\r
 \r
-            public string GetNotice()\r
+            public string GetNotice(DateTime start, DateTime prev, DateTime now)\r
             {\r
-                var now = DateTime.Now;\r
-                if (Start == DateTime.MinValue)\r
-                    return "";\r
-                var pr = _prev;\r
-                _prev = now;\r
-                if (pr == DateTime.MinValue)\r
-                    return "";\r
-                var m20 = TimeSpan.FromMinutes(20);\r
-                if (pr - Start < m20 && now - Start >= m20)\r
-                    return "20分経過しました。";\r
-                var margin = TimeSpan.Zero;\r
-                var msg = string.Join(" ", from e in _times.Zip(_target, (times, ship) => new {times, ship})\r
-                    where e.times != null && e.times.Any(rt => rt.Time - pr > margin && rt.Time - now <= margin)\r
+                var msg = string.Join(" ", from e in _spans.Zip(_target, (spans, ship) => new {spans, ship})\r
+                    where e.spans != null && e.spans.Any(\r
+                        s => s.Span - (prev - start) > TimeSpan.Zero && s.Span - (now - start) <= TimeSpan.Zero)\r
                     select e.ship.Name);\r
                 return msg == "" ? "" : "修理進行: " + msg;\r
             }\r
@@ -143,11 +121,22 @@ namespace KancolleSniffer
 \r
         public void SetTimer(bool port = false)\r
         {\r
+            var cont = false;\r
             for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
-                SetTimer(fleet, port);\r
+            {\r
+                if (CheckFleet(fleet, port))\r
+                    cont = true;\r
+            }\r
+            if (!cont)\r
+            {\r
+                _start = DateTime.MinValue;\r
+                return;\r
+            }\r
+            if (_start == DateTime.MinValue)\r
+                _start = DateTime.Now;\r
         }\r
 \r
-        private void SetTimer(int fleet, bool port)\r
+        private bool CheckFleet(int fleet, bool port)\r
         {\r
             var deck = _shipInfo.GetDeck(fleet);\r
             var repair = _repairStatuses[fleet];\r
@@ -155,36 +144,29 @@ namespace KancolleSniffer
             if (!_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) || _shipInfo.InMission(fleet))\r
             {\r
                 repair.Invalidate();\r
-                return;\r
+                return false;\r
             }\r
             if (repair.DeckChanged(deck))\r
+            {\r
+                _start = DateTime.MinValue;\r
                 repair.Invalidate();\r
+            }\r
             repair.Deck = deck.ToArray();\r
             var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\r
-            var target = (from id in deck.Take(cap) select IsRepairable(id) ? _shipInfo[id] : new ShipStatus()).ToArray();\r
+            var target =\r
+                (from id in deck.Take(cap) select IsRepairable(id) ? _shipInfo[id] : new ShipStatus()).ToArray();\r
             var totalHp = target.Sum(s => s.NowHp);\r
             if (totalHp == 0)\r
             {\r
                 repair.Invalidate();\r
-                return;\r
+                return false;\r
             }\r
             if (totalHp == repair.TotalHp)\r
-                return;\r
-            /*\r
-             * 母港に遷移したときに、耐久値が回復しているか修理開始から20分経過しているときに\r
-             * タイマーをリスタートする。\r
-             * \r
-             * Q. なぜ20分でリスタートするのか?\r
-             * \r
-             * A. 明石の修理は戦闘中も続くので、戦闘中に修理開始から20分経つと母港に戻った\r
-             *    ときに耐久値が回復する。最後の戦闘で損傷すると、損傷と回復が同時に耐久値に\r
-             *    反映されて回復が起こったことがわからない。耐久値の回復だけを基準にすると\r
-             *    リスタートできないので、20分経過していたらリスタートする。\r
-            */\r
-            if (repair.Start == DateTime.MinValue ||\r
-                (port && (totalHp > repair.TotalHp || (DateTime.Now - repair.Start).TotalMinutes > 20)))\r
-                repair.Start = DateTime.Now;\r
+                return true;\r
+            if (port && repair.TotalHp > 0 && totalHp != repair.TotalHp)\r
+                _start = DateTime.MinValue;\r
             repair.UpdateTarget(target);\r
+            return true;\r
         }\r
 \r
         private bool IsRepairable(int id)\r
@@ -195,12 +177,21 @@ namespace KancolleSniffer
 \r
         public RepairSpan[] GetTimers(int fleet)\r
         {\r
-            return _repairStatuses[fleet].GetTimers();\r
+            if (_start == DateTime.MinValue)\r
+                return new RepairSpan[0];\r
+            return _repairStatuses[fleet].GetTimers(_start, DateTime.Now);\r
         }\r
 \r
         public string[] GetNotice()\r
         {\r
-            return _repairStatuses.Select(repair => repair.GetNotice()).ToArray();\r
+            var now = DateTime.Now;\r
+            var prev = _prev;\r
+            _prev = now;\r
+            if (prev == DateTime.MinValue || _start == DateTime.MinValue)\r
+                return new string[0];\r
+            if (prev - _start < TimeSpan.FromMinutes(20) && now - _start >= TimeSpan.FromMinutes(20))\r
+                return new[] {"20分経過しました。"};\r
+            return _repairStatuses.Select(repair => repair.GetNotice(_start, prev, now)).ToArray();\r
         }\r
     }\r
 }
\ No newline at end of file
index 9b0f2ae..6c3276b 100644 (file)
@@ -381,13 +381,19 @@ namespace KancolleSniffer
         private void NotifyAkashiTimer()\r
         {\r
             var msgs = _sniffer.GetAkashiTimerNotice();\r
+            if (msgs.Length == 0)\r
+                return;\r
+            if (msgs[0] == "20分経過しました。")\r
+            {\r
+                _noticeQueue.Enqueue("泊地修理", msgs[0], _config.Akashi20MinSoundFile);\r
+                return;\r
+            }\r
             var fn = new[] {"第一艦隊", "第二艦隊", "第三艦隊", "第四艦隊"};\r
             for (var i = 0; i < fn.Length; i++)\r
             {\r
                 if (msgs[i] == "")\r
                     continue;\r
-                var sound = msgs[i] == "20分経過しました。" ? _config.Akashi20MinSoundFile : _config.AkashiProgressSoundFile;\r
-                _noticeQueue.Enqueue("泊地修理 " + fn[i], msgs[i], sound);\r
+                _noticeQueue.Enqueue("泊地修理 " + fn[i], msgs[i], _config.AkashiProgressSoundFile);\r
             }\r
         }\r
 \r
index af06cc5..1a808de 100644 (file)
@@ -73,12 +73,12 @@ namespace KancolleSniffer
 \r
         public TimeSpan RepairTime\r
         {\r
-            get { return CalcRepairTime(MaxHp - NowHp); }\r
+            get { return TimeSpan.FromSeconds(CalcRepairSec(MaxHp - NowHp) + 30); }\r
         }\r
 \r
-        public TimeSpan CalcRepairTime(int damage)\r
+        public int CalcRepairSec(int damage)\r
         {\r
-            return TimeSpan.FromSeconds(RepairSecPerHp * damage + 30);\r
+            return (int)(RepairSecPerHp * damage);\r
         }\r
 \r
         public double RepairSecPerHp\r