// 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
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
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
\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
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
\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