OSDN Git Service

明石タイマーの実装を正確にする
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Sun, 8 Nov 2015 07:31:07 +0000 (16:31 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Sun, 8 Nov 2015 15:04:15 +0000 (00:04 +0900)
KancolleSniffer/AkashiTimer.cs

index 5c8b912..1ade2e3 100644 (file)
@@ -51,6 +51,8 @@ namespace KancolleSniffer
                 set { _deck = value; }\r
             }\r
 \r
+            public State State { get; set; }\r
+\r
             public void Invalidate()\r
             {\r
                 _target = new ShipStatus[0];\r
@@ -63,8 +65,6 @@ namespace KancolleSniffer
                 _target = target;\r
             }\r
 \r
-            public bool IsRepaired(ShipStatus[] target) => _target.Zip(target, (a, b) => a.NowHp < b.NowHp).Any(x => x);\r
-\r
             public RepairSpan[] GetTimers(DateTime start, DateTime now)\r
             {\r
                 var spent = TimeSpan.FromSeconds((int)(now - start).TotalSeconds);\r
@@ -148,75 +148,73 @@ namespace KancolleSniffer
                 _repairStatuses[i] = new RepairStatus();\r
         }\r
 \r
+        [Flags]\r
+        private enum State\r
+        {\r
+            Stop = 0,\r
+            Continue = 1,\r
+            Reset = 2,\r
+            Reparing = 4\r
+        }\r
+\r
         public void SetTimer(bool port = false)\r
         {\r
-            var cont = false;\r
+            var now = DateTime.Now;\r
             for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
+                CheckFleet(fleet);\r
+            if (_repairStatuses.Any(r => (r.State & State.Reset) == State.Reset))\r
             {\r
-                if (CheckFleet(fleet, port))\r
-                    cont = true;\r
+                _start = now;\r
+                return;\r
             }\r
-            if (!cont)\r
+            if (port && now - _start > TimeSpan.FromMinutes(20))\r
             {\r
-                _start = DateTime.MinValue;\r
-                return;\r
+                if (_repairStatuses.Any(r => (r.State & State.Reparing) == State.Reparing))\r
+                    _start = now;\r
+                else if (_repairStatuses.All(r => (r.State & State.Continue) == 0))\r
+                    _start = DateTime.MinValue;\r
+            }\r
+            else if (_repairStatuses.Any(r => (r.State & State.Continue) != 0))\r
+            {\r
+                if (_start == DateTime.MinValue)\r
+                    _start = now;\r
             }\r
-            if (_start == DateTime.MinValue)\r
-                _start = DateTime.Now;\r
         }\r
 \r
-        private bool CheckFleet(int fleet, bool port)\r
+        private void CheckFleet(int fleet)\r
         {\r
-            var deck = _shipInfo.GetDeck(fleet);\r
+            var deck = _shipInfo.GetDeck(fleet).ToArray();\r
             var repair = _repairStatuses[fleet];\r
             var fs = _shipInfo.GetStatus(deck[0]);\r
-            if (!fs.Name.StartsWith("明石") || _dockInfo.InNDock(fs.Id) || _shipInfo.InMission(fleet))\r
-            {\r
-                repair.Invalidate();\r
-                return false;\r
-            }\r
-            if (repair.DeckChanged(deck))\r
+            /*\r
+             * 旗艦が明石でないか明石がドックに入っている場合は泊地修理を止める。\r
+            */\r
+            if (!fs.Name.StartsWith("明石") || _shipInfo.InMission(fleet))\r
             {\r
-                _start = DateTime.MinValue;\r
                 repair.Invalidate();\r
+                repair.State = State.Stop;\r
+                repair.Deck = deck;\r
+                return;\r
             }\r
-            repair.Deck = deck.ToArray();\r
             var cap = fs.Slot.Count(item => item.Spec.Name == "艦艇修理施設") + 2;\r
-            var target = deck.Take(cap).Select(id =>\r
-            {\r
-                /*\r
-                 * 修理できない艦娘のステータスをNowHp == MaxHpにする。\r
-                 * - 入渠中の艦娘\r
-                 *   入渠が終了して戻ったのを明石による回復と誤認しないためにHPを回復時の値に\r
-                 * - 中破以上の艦娘\r
-                 *   出撃中の損傷で小破以下から中破以上になったのを回復と誤認しないためにHPを0に\r
-                */\r
-                var s = _shipInfo.GetStatus(id);\r
-                var full = new ShipStatus {NowHp = s.MaxHp, MaxHp = s.MaxHp};\r
-                var zero = new ShipStatus();\r
-                return _dockInfo.InNDock(id)\r
-                    ? full\r
-                    : s.DamageLevel >= ShipStatus.Damage.Half ? zero : s;\r
-            }).ToArray();\r
-            var damage = target.Sum(s => s.MaxHp - s.NowHp);\r
-            if (damage == 0)\r
-            {\r
-                repair.Invalidate();\r
-                return false;\r
-            }\r
             /*\r
-             * 母港に遷移したときに、耐久値が回復しているか修理開始から20分経過している\r
-             * ときにタイマーをリスタートする。\r
-             *\r
-             * 泊地修理中に出撃して母港に戻ったときに、修理開始から20分以上経っていると\r
-             * HPが回復する。最後の戦闘の損傷と回復量が差し引きゼロだと泊地修理の進行が\r
-             * わからないので、20分経っていたらとにかくリスタートする。\r
+             * 泊地修理の条件を満たさない艦はMaxHp==NowHpのダミーを設定する。\r
+             * 入渠中の艦娘は終わったときに回復扱いされないようNowHp=MaxHpにする。\r
+             * 中破以上でNowHp=MaxHpにすると回復扱いされるのでNowHp=MaxHp=0にする。\r
             */\r
-            if (port && _start != DateTime.MinValue &&\r
-                (repair.IsRepaired(target) || DateTime.Now - _start > TimeSpan.FromMinutes(20)))\r
-                _start = DateTime.MinValue;\r
+            var target = (from id in deck.Take(cap)\r
+                let s = _shipInfo.GetStatus(id)\r
+                let full = new ShipStatus {NowHp = s.MaxHp, MaxHp = s.MaxHp}\r
+                let zero = new ShipStatus()\r
+                select _dockInfo.InNDock(id) ? full : s.DamageLevel >= ShipStatus.Damage.Half ? zero : s).ToArray();\r
+            repair.State = State.Continue;\r
+            if (repair.DeckChanged(deck))\r
+                repair.State |= State.Reset;\r
+            if (target[0].DamageLevel < ShipStatus.Damage.Half &&\r
+                target.Any(s => s.NowHp < s.MaxHp))\r
+                repair.State |= State.Reparing;\r
             repair.UpdateTarget(target);\r
-            return true;\r
+            repair.Deck = deck;\r
         }\r
 \r
         public RepairSpan[] GetTimers(int fleet)\r