X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=KancolleSniffer%2FAkashiTimer.cs;h=e59a887afbbd5443639fc734af32c17ccb5a8b16;hb=84499fc67c900557b5430a74ea0f74bcc1349116;hp=f6b12474b7a3abc50b6ffeac7ad336d989d30972;hpb=622490684e467ae5c0ab8e432393dca661328e06;p=kancollesniffer%2FKancolleSniffer.git diff --git a/KancolleSniffer/AkashiTimer.cs b/KancolleSniffer/AkashiTimer.cs index f6b1247..e59a887 100644 --- a/KancolleSniffer/AkashiTimer.cs +++ b/KancolleSniffer/AkashiTimer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2014, 2015 Kazuhiro Fujieda +// Copyright (C) 2014, 2015 Kazuhiro Fujieda // // This program is part of KancolleSniffer. // @@ -18,13 +18,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Web; namespace KancolleSniffer { public class AkashiTimer { private readonly ShipInfo _shipInfo; - private readonly ItemInfo _itemInfo; private readonly DockInfo _dockInfo; private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount]; private DateTime _start; @@ -45,7 +45,6 @@ namespace KancolleSniffer private class RepairStatus { private ShipStatus[] _target = new ShipStatus[0]; - private RepairSpan[][] _spans = new RepairSpan[0][]; private int[] _deck = new int[0]; public int[] Deck @@ -53,145 +52,202 @@ namespace KancolleSniffer set { _deck = value; } } - public void Invalidate() - { - _target = new ShipStatus[0]; - _spans = new RepairSpan[0][]; - } + public State State { get; set; } - public int TotalHp - { - get { return _target.Sum(s => s.NowHp); } - } + public bool IsRepaired(ShipStatus[] target) => _target.Zip(target, (a, b) => a.NowHp < b.NowHp).Any(x => x); - public bool DeckChanged(IEnumerable deck) - { - return !_deck.SequenceEqual(deck); - } + public bool DeckChanged(IEnumerable deck) => !_deck.SequenceEqual(deck); public void UpdateTarget(ShipStatus[] target) { _target = target; - CalcRepairSpan(); - } - - private void CalcRepairSpan() - { - _spans = (from s in _target - let damage = s.MaxHp - s.NowHp - let first = new RepairSpan(0, TimeSpan.FromMinutes(20)) - select damage == 0 - ? null - : new[] {first}.Concat(from d in Enumerable.Range(2, damage < 2 ? 0 : damage - 1) - let sec = s.CalcRepairSec(d) + 60 - where sec > 20 * 60 - select new RepairSpan(d - 1, TimeSpan.FromSeconds(sec))).ToArray()).ToArray(); } public RepairSpan[] GetTimers(DateTime start, DateTime now) { - var span = TimeSpan.FromSeconds((int)(now - start).TotalSeconds); - return (from spans in _spans - select spans == null - ? new RepairSpan(0, TimeSpan.MinValue) - : (from s in spans select new RepairSpan(s.Diff, s.Span - span)) - .FirstOrDefault(s => s.Span > TimeSpan.Zero) - ?? new RepairSpan(spans.Last().Diff + 1, TimeSpan.Zero) - ).ToArray(); + var spent = TimeSpan.FromSeconds((int)(now - start).TotalSeconds); + return _target.Select(s => + { + var damage = s.MaxHp - s.NowHp; + if (damage == 0) + return new RepairSpan(0, TimeSpan.MinValue); + if (spent < TimeSpan.FromMinutes(20)) + return new RepairSpan(0, TimeSpan.FromMinutes(20) - spent); + if (damage == 1) + return new RepairSpan(1, TimeSpan.Zero); + for (var d = 2; d <= damage; d++) + { + var sec = s.CalcRepairSec(d) + 60; + if (sec <= 20 * 60) + continue; + if (TimeSpan.FromSeconds(sec) > spent) + return new RepairSpan(d - 1, TimeSpan.FromSeconds(sec) - spent); + } + return new RepairSpan(damage, TimeSpan.Zero); + }).ToArray(); } - public string GetNotice(DateTime start, DateTime prev, DateTime now) + public Notice GetNotice(DateTime start, DateTime prev, DateTime now) { - var msg = string.Join(" ", from e in _spans.Zip(_target, (spans, ship) => new {spans, ship}) - where e.spans != null && e.spans.Any( - s => s.Span - (prev - start) > TimeSpan.Zero && s.Span - (now - start) <= TimeSpan.Zero) - select e.ship.Name); - return msg == "" ? "" : "修理進行: " + msg; + var m20 = TimeSpan.FromMinutes(20); + var proc = new List(); + var comp = new List(); + foreach (var s in _target) + { + var damage = s.MaxHp - s.NowHp; + if (damage == 0) + continue; + if (damage == 1) + { + if (prev - start < m20 && now - start >= m20) + comp.Add(s.Name); + continue; + } + // スリープで時間が飛んだときに修理完了だけを表示するために、 + // 完全回復から減らしながら所要時間と経過時間と比較する。 + for (var d = damage; d >= 2; d--) + { + var sec = s.CalcRepairSec(d) + 60; + if (sec <= 20 * 60) + { + if (d == damage && (prev - start < m20 && now - start >= m20)) + comp.Add(s.Name); + continue; + } + var span = TimeSpan.FromSeconds(sec); + if (span <= prev - start || now - start < span) + continue; + if (d == damage) + comp.Add(s.Name); + else + proc.Add(s.Name); + break; + } + } + return new Notice + { + Proceeded = proc.Count == 0 ? "" : string.Join(" ", proc), + Completed = comp.Count == 0 ? "" : string.Join(" ", comp) + }; } } - public AkashiTimer(ShipInfo ship, ItemInfo item, DockInfo dock) + public class Notice + { + public string Proceeded { get; set; } + public string Completed { get; set; } + } + + public AkashiTimer(ShipInfo ship, DockInfo dock) { _shipInfo = ship; - _itemInfo = item; _dockInfo = dock; for (var i = 0; i < _repairStatuses.Length; i++) _repairStatuses[i] = new RepairStatus(); } - public void SetTimer(bool port = false) + private enum State { - var cont = false; - for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++) - { - if (CheckFleet(fleet, port)) - cont = true; - } - if (!cont) - { - _start = DateTime.MinValue; + Continue = 0, + Reset = 1, + } + + public void Port() + { + CheckFleet(); + var now = DateTime.Now; + var reset = _repairStatuses.Any(r => r.State == State.Reset); + if (_start == DateTime.MinValue || now - _start > TimeSpan.FromMinutes(20) || reset) + _start = now; + } + + public void InspectChange(string request) + { + CheckFleet(); + var values = HttpUtility.ParseQueryString(request); + if (int.Parse(values["api_ship_idx"]) == -1) return; - } - if (_start == DateTime.MinValue) + if (_repairStatuses.Any(r => r.State == State.Reset)) _start = DateTime.Now; } - private bool CheckFleet(int fleet, bool port) + public void CheckFleet() + { + for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++) + CheckFleet(fleet); + } + + private void CheckFleet(int fleet) { - var deck = _shipInfo.GetDeck(fleet); + var deck = _shipInfo.GetDeck(fleet).ToArray(); var repair = _repairStatuses[fleet]; - var fs = deck[0]; - if (!_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) || _shipInfo.InMission(fleet)) + var fs = _shipInfo.GetStatus(deck[0]); + repair.State = State.Continue; + if (!fs.Spec.IsRepairShip) { - repair.Invalidate(); - return false; + repair.UpdateTarget(new ShipStatus[0]); + repair.Deck = deck; + return; } if (repair.DeckChanged(deck)) { - _start = DateTime.MinValue; - repair.Invalidate(); + repair.State = State.Reset; + repair.Deck = deck; } - repair.Deck = deck.ToArray(); - var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2; - var target = - (from id in deck.Take(cap) select IsRepairable(id) ? _shipInfo[id] : new ShipStatus()).ToArray(); - var totalHp = target.Sum(s => s.NowHp); - if (totalHp == 0) - { - repair.Invalidate(); - return false; - } - if (totalHp == repair.TotalHp) - return true; - if (port && repair.TotalHp > 0 && totalHp != repair.TotalHp) - _start = DateTime.MinValue; + var target = RepairTarget(deck); + if (repair.IsRepaired(target)) + repair.State = State.Reset; repair.UpdateTarget(target); - return true; } - private bool IsRepairable(int id) + private ShipStatus[] RepairTarget(int[] deck) { - var s = _shipInfo[id]; - return !_dockInfo.InNDock(id) && s.NowHp < s.MaxHp && s.DamageLevel < ShipStatus.Damage.Half; + var fs = _shipInfo.GetStatus(deck[0]); + if (fs.DamageLevel >= ShipStatus.Damage.Half) + return new ShipStatus[0]; + var cap = fs.Slot.Count(item => item.Spec.IsRepairFacility) + 2; + /* + * 泊地修理の条件を満たさない艦はMaxHp==NowHpのダミーを設定する。 + * - 入渠中の艦娘は終わったときに回復扱いされないようNowHp=MaxHpに + * - 中破以上でNowHp=MaxHpにすると回復扱いされるのでNowHp=MaxHp=0に + */ + return (from id in deck.Take(cap) + let s = _shipInfo.GetStatus(id) + let full = new ShipStatus {NowHp = s.MaxHp, MaxHp = s.MaxHp} + let zero = new ShipStatus() + select _dockInfo.InNDock(id) ? full : s.DamageLevel >= ShipStatus.Damage.Half ? zero : s).ToArray(); } public RepairSpan[] GetTimers(int fleet) + => _start == DateTime.MinValue ? new RepairSpan[0] : _repairStatuses[fleet].GetTimers(_start, DateTime.Now); + + public TimeSpan PresetDeckTimer { - if (_start == DateTime.MinValue) - return new RepairSpan[0]; - return _repairStatuses[fleet].GetTimers(_start, DateTime.Now); + get + { + if (_start == DateTime.MinValue) + return TimeSpan.MinValue; + var r = _start + TimeSpan.FromMinutes(20) - DateTime.Now; + return r >= TimeSpan.Zero ? r : TimeSpan.Zero; + } } - public string[] GetNotice() + public bool CheckReparing(int fleet) => GetTimers(fleet).Any(r => r.Span != TimeSpan.MinValue); + + public bool CheckReparing() => Enumerable.Range(0, ShipInfo.FleetCount).Any(CheckReparing); + + public Notice[] GetNotice() { var now = DateTime.Now; var prev = _prev; _prev = now; if (prev == DateTime.MinValue || _start == DateTime.MinValue) - return new string[0]; - if (prev - _start < TimeSpan.FromMinutes(20) && now - _start >= TimeSpan.FromMinutes(20)) - return new[] {"20分経過しました。"}; - return _repairStatuses.Select(repair => repair.GetNotice(_start, prev, now)).ToArray(); + return new Notice[0]; + var r = _repairStatuses.Select(repair => repair.GetNotice(_start, prev, now)).ToArray(); + var m20 = TimeSpan.FromMinutes(20); + if (prev - _start < m20 && now - _start >= m20) + r[0].Proceeded = "20分経過しました。"; + return r; } } } \ No newline at end of file