-// Copyright (C) 2013, 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// Copyright (C) 2013, 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
// \r
-// This program is part of KancolleSniffer.\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
-// 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
+// http://www.apache.org/licenses/LICENSE-2.0\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
+// 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 readonly int[] _cond = new int[ShipInfo.FleetCount];\r
- private readonly TimeSpan[] _prevLeftTimes = new TimeSpan[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
}\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
- if (!_enable[fleet]) // タイマーが無効なら前回の残り時間を無効にする\r
- _prevLeftTimes[fleet] = TimeSpan.MinValue;\r
- if (_shipInfo.InMission(fleet) || _shipInfo.InSortie(fleet))\r
- continue;\r
- _enable[fleet] = true;\r
- var cond = _cond[fleet] = CondMin(fleet);\r
- if (cond < 49 && _times[fleet] != DateTime.MinValue) // 計時中\r
- {\r
- // コンディション値から推定される残り時刻と経過時間の差\r
- var diff = TimeSpan.FromMinutes((49 - cond + 2) / 3 * 3) - (_times[fleet] - DateTime.Now);\r
- if (diff >= TimeSpan.Zero && diff <= TimeSpan.FromMinutes(3)) // 差が0以上3分以内ならタイマーを更新しない。\r
- return;\r
- }\r
- _times[fleet] = cond < 49\r
- ? DateTime.Now.AddMinutes((49 - 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
- public void Invalidate(int fleet)\r
+ private DateTime NextRegenTime(DateTime now)\r
{\r
- _enable[fleet] = _cond[fleet] == CondMin(fleet);\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
- public void Disable(int fleet)\r
+ private void ResetRegenTime(DateTime now)\r
{\r
- _enable[fleet] = false;\r
+ _regenTime = (double)now.Ticks / TimeSpan.TicksPerSecond % Interval;\r
+ NeedSave = true;\r
}\r
\r
- private int CondMin(int fleet)\r
+ public void InvalidateCond()\r
{\r
- return (from id in _shipInfo.GetDeck(fleet) where id != -1 select _shipInfo[id].Cond)\r
- .DefaultIfEmpty(49).Min();\r
+ _lastCond = int.MinValue;\r
+ }\r
+\r
+ public void CheckCond()\r
+ {\r
+ if (_lastCond != _shipInfo.ShipList.Min(s => s.Cond))\r
+ _lastCond = int.MinValue;\r
}\r
\r
public DateTime GetTimer(int fleet)\r
{\r
- return _enable[fleet] ? _times[fleet] : DateTime.MinValue;\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[_times.Length];\r
- for (var f = 0; f < _times.Length; f++)\r
+ var result = new int[ShipInfo.FleetCount];\r
+ var now = DateTime.Now;\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
- var now = _times[f] == DateTime.MinValue ? TimeSpan.Zero : _times[f] - DateTime.Now;\r
- var prev = _prevLeftTimes[f];\r
- _prevLeftTimes[f] = now;\r
- if (prev == TimeSpan.MinValue)\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 > TimeSpan.FromMinutes(9) && now <= TimeSpan.FromMinutes(9))\r
+ if (prev < timer.AddMinutes(-9) && now >= timer.AddMinutes(-9))\r
result[f] = 40;\r
- else if (prev > TimeSpan.Zero && now <= TimeSpan.Zero)\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