OSDN Git Service

DPIスケーリング時に連合艦隊表示がずれるのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ConditionTimer.cs
index 393ff44..215e632 100644 (file)
-using System;\r
+// Copyright (C) 2013, 2014, 2015 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.Linq;\r
 \r
 namespace KancolleSniffer\r
 {\r
-    public class ConditionTimer\r
+    public class ConditionTimer : IHaveState\r
     {\r
         private readonly ShipInfo _shipInfo;\r
-        private readonly DateTime[][] _times = new DateTime[ShipInfo.FleetCount][];\r
-        private readonly bool[] _enable = new bool[ShipInfo.FleetCount];\r
+        private const int Interval = 180;\r
+        private int _lastCond = int.MinValue;\r
+        private DateTime _lastUpdate;\r
+        private double _regenTime;\r
+        private DateTime _prevNotice;\r
+\r
+        public bool NeedSave { get; private set; }\r
 \r
         public ConditionTimer(ShipInfo shipInfo)\r
         {\r
             _shipInfo = shipInfo;\r
-            for (var f = 0; f < _times.Length; f++)\r
-                _times[f] = new DateTime[3];\r
         }\r
 \r
-        public void SetTimer()\r
+        public void CalcRegenTime()\r
         {\r
-            for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
+            var now = DateTime.Now;\r
+            var prevTime = _lastUpdate;\r
+            var prevCond = _lastCond;\r
+            _lastUpdate = now;\r
+            _lastCond = _shipInfo.ShipList.Min(s => s.Cond);\r
+// ReSharper disable once CompareOfFloatsByEqualityOperator\r
+            if (_regenTime == double.MinValue)\r
             {\r
-                _enable[fleet] = true;\r
-                var cond =\r
-                    (from id in _shipInfo.GetDeck(fleet) where id != -1 select _shipInfo[id].Cond)\r
-                        .DefaultIfEmpty(49).Min();\r
-                var time49 = _times[fleet][2];\r
-                if (cond < 49 && time49 != DateTime.MinValue) // 計時中\r
-                {\r
-                    // コンディション値から推定される残り時刻と経過時間の差\r
-                    var diff = TimeSpan.FromMinutes((49 - cond + 2) / 3 * 3) - (time49 - DateTime.Now);\r
-                    if (diff >= TimeSpan.Zero && diff <= TimeSpan.FromMinutes(3)) // 差が0以上3分以内ならタイマーを更新しない。\r
-                        return;\r
-                }\r
-                var thresh = new[] {30, 40, 49};\r
-                for (var i = 0; i < thresh.Length; i++)\r
-                    _times[fleet][i] = cond < thresh[i]\r
-                        ? DateTime.Now.AddMinutes((thresh[i] - cond + 2) / 3 * 3)\r
-                        : DateTime.MinValue;\r
+                ResetRegenTime(now);\r
+                return;\r
             }\r
+            if (prevCond == int.MinValue || prevCond == _lastCond)\r
+                return;\r
+            var next = NextRegenTime(prevTime);\r
+            var ticks = next > now ? 0 : (int)(now - next).TotalSeconds / Interval + 1;\r
+            var diff = (_lastCond - prevCond + 2) / 3 - ticks;\r
+            if (_lastCond == 49 ? diff > 0 : diff != 0)\r
+                ResetRegenTime(now);\r
+        }\r
+\r
+        private DateTime NextRegenTime(DateTime now)\r
+        {\r
+            var batch = new DateTime((long)((now.Ticks / TimeSpan.TicksPerSecond / Interval * Interval + _regenTime) *\r
+                                            TimeSpan.TicksPerSecond));\r
+            return batch < now ? batch.AddSeconds(Interval) : batch;\r
+        }\r
+\r
+        private void ResetRegenTime(DateTime now)\r
+        {\r
+            _regenTime = (double)now.Ticks / TimeSpan.TicksPerSecond % Interval;\r
+            NeedSave = true;\r
+        }\r
+\r
+        public void InvalidateCond()\r
+        {\r
+            _lastCond = int.MinValue;\r
         }\r
 \r
-        public void Disable(int fleet)\r
+        public void CheckCond()\r
         {\r
-            _enable[fleet] = false;\r
+            if (_lastCond != _shipInfo.ShipList.Min(s => s.Cond))\r
+                _lastCond = int.MinValue;\r
         }\r
 \r
-        public string[] GetTimerStrings(int fleet)\r
+        public DateTime GetTimer(int fleet)\r
         {\r
-            if (!_enable[fleet])\r
-                return new[] {"無効", "無効", "無効"};\r
+            if (_shipInfo.InMission(fleet) || _shipInfo.InSortie(fleet))\r
+                return DateTime.MinValue;\r
+            var cond = _shipInfo.GetShipStatuses(fleet).Select(s => s.Cond).DefaultIfEmpty(49).Min();\r
+            if (cond >= 49)\r
+                return DateTime.MinValue;\r
+            var nextRegen = NextRegenTime(_lastUpdate);\r
+            return cond >= 46 ? nextRegen : nextRegen.AddSeconds((46 - cond + 2) / 3 * Interval);\r
+        }\r
+\r
+        public int[] GetNotice()\r
+        {\r
+            var result = new int[ShipInfo.FleetCount];\r
             var now = DateTime.Now;\r
-            return\r
-                (from time in _times[fleet] select time > now ? (time - now).ToString(@"mm\:ss") : "00:00")\r
-                    .ToArray();\r
+            var prev = _prevNotice;\r
+            _prevNotice = now;\r
+            if (prev == DateTime.MinValue)\r
+                return result;\r
+            for (var f = 0; f < result.Length; f++)\r
+            {\r
+                if (_shipInfo.InMission(f) || _shipInfo.InSortie(f))\r
+                    continue;\r
+                var timer = GetTimer(f);\r
+                if (timer == DateTime.MinValue || prev < _lastUpdate)\r
+                    continue;\r
+                if (prev < timer.AddMinutes(-9) && now >= timer.AddMinutes(-9))\r
+                    result[f] = 40;\r
+                else if (prev < timer && now >= timer)\r
+                    result[f] = 49;\r
+            }\r
+            return result;\r
+        }\r
+\r
+        public void SaveState(Status status)\r
+        {\r
+            NeedSave = false;\r
+            status.CondRegenTime = _regenTime;\r
+        }\r
+\r
+        public void LoadState(Status status)\r
+        {\r
+            _regenTime = status.CondRegenTime;\r
         }\r
     }\r
 }
\ No newline at end of file