-// Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// Copyright (C) 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.Collections.Generic;\r
public class AkashiTimer\r
{\r
private readonly ShipInfo _shipInfo;\r
- private readonly ItemInfo _itemInfo;\r
private readonly DockInfo _dockInfo;\r
private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
private DateTime _start;\r
set { _deck = value; }\r
}\r
\r
- public void Invalidate()\r
- {\r
- _target = new ShipStatus[0];\r
- }\r
+ public State State { get; set; }\r
\r
- public int TotalHp\r
- {\r
- get { return _target.Sum(s => s.NowHp); }\r
- }\r
+ public bool IsRepaired(ShipStatus[] target) => _target.Zip(target, (a, b) => a.NowHp < b.NowHp).Any(x => x);\r
\r
- public bool DeckChanged(IEnumerable<int> deck)\r
- {\r
- return !_deck.SequenceEqual(deck);\r
- }\r
+ public bool DeckChanged(IEnumerable<int> deck) => !_deck.SequenceEqual(deck);\r
\r
public void UpdateTarget(ShipStatus[] target)\r
{\r
}).ToArray();\r
}\r
\r
- public string GetNotice(DateTime start, DateTime prev, DateTime now)\r
+ public Notice GetNotice(DateTime start, DateTime prev, DateTime now)\r
{\r
- var msg = string.Join(" ", _target.Where(s =>\r
+ var m20 = TimeSpan.FromMinutes(20);\r
+ var proc = new List<string>();\r
+ var comp = new List<string>();\r
+ foreach (var s in _target)\r
{\r
var damage = s.MaxHp - s.NowHp;\r
- if (damage < 2)\r
- return false;\r
- for (var d = 2; d <= damage; d++)\r
+ if (damage == 0)\r
+ continue;\r
+ if (damage == 1)\r
+ {\r
+ if (prev - start < m20 && now - start >= m20)\r
+ comp.Add(s.Name);\r
+ continue;\r
+ }\r
+ // スリープで時間が飛んだときに修理完了だけを表示するために、\r
+ // 完全回復から減らしながら所要時間と経過時間と比較する。\r
+ for (var d = damage; d >= 2; d--)\r
{\r
var sec = s.CalcRepairSec(d) + 60;\r
if (sec <= 20 * 60)\r
+ {\r
+ if (d == damage && (prev - start < m20 && now - start >= m20))\r
+ comp.Add(s.Name);\r
continue;\r
+ }\r
var span = TimeSpan.FromSeconds(sec);\r
- if (span > prev - start && span <= now - start)\r
- return true;\r
+ if (span <= prev - start || now - start < span)\r
+ continue;\r
+ if (d == damage)\r
+ comp.Add(s.Name);\r
+ else\r
+ proc.Add(s.Name);\r
+ break;\r
}\r
- return false;\r
- }).Select(s => s.Name));\r
- return msg == "" ? "" : "修理進行: " + msg;\r
+ }\r
+ return new Notice\r
+ {\r
+ Proceeded = proc.Count == 0 ? "" : string.Join(" ", proc),\r
+ Completed = comp.Count == 0 ? "" : string.Join(" ", comp)\r
+ };\r
}\r
}\r
\r
- public AkashiTimer(ShipInfo ship, ItemInfo item, DockInfo dock)\r
+ public class Notice\r
+ {\r
+ public string Proceeded { get; set; }\r
+ public string Completed { get; set; }\r
+ }\r
+\r
+ public AkashiTimer(ShipInfo ship, DockInfo dock)\r
{\r
_shipInfo = ship;\r
- _itemInfo = item;\r
_dockInfo = dock;\r
for (var i = 0; i < _repairStatuses.Length; i++)\r
_repairStatuses[i] = new RepairStatus();\r
}\r
\r
- public void SetTimer(bool port = false)\r
+ private enum State\r
{\r
- var cont = false;\r
- for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
- {\r
- if (CheckFleet(fleet, port))\r
- cont = true;\r
- }\r
- if (!cont)\r
- {\r
- _start = DateTime.MinValue;\r
+ Continue = 0,\r
+ Reset = 1,\r
+ }\r
+\r
+ public void Port()\r
+ {\r
+ CheckFleet();\r
+ var now = DateTime.Now;\r
+ var reset = _repairStatuses.Any(r => r.State == State.Reset);\r
+ if (_start == DateTime.MinValue || now - _start > TimeSpan.FromMinutes(20) || reset)\r
+ _start = now;\r
+ }\r
+\r
+ public void InspectChange(string request)\r
+ {\r
+ CheckFleet();\r
+ var values = HttpUtility.ParseQueryString(request);\r
+ if (int.Parse(values["api_ship_idx"]) == -1)\r
return;\r
- }\r
- if (_start == DateTime.MinValue)\r
+ if (_repairStatuses.Any(r => r.State == State.Reset))\r
_start = DateTime.Now;\r
}\r
\r
- private bool CheckFleet(int fleet, bool port)\r
+ public void CheckFleet()\r
{\r
- var deck = _shipInfo.GetDeck(fleet);\r
+ for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
+ CheckFleet(fleet);\r
+ }\r
+\r
+ private void CheckFleet(int fleet)\r
+ {\r
+ var deck = _shipInfo.GetDeck(fleet).ToArray();\r
var repair = _repairStatuses[fleet];\r
- var fs = deck[0];\r
- if (!_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) || _shipInfo.InMission(fleet))\r
+ var fs = _shipInfo.GetStatus(deck[0]);\r
+ repair.State = State.Continue;\r
+ if (!fs.Spec.IsRepairShip)\r
{\r
- repair.Invalidate();\r
- return false;\r
+ repair.UpdateTarget(new ShipStatus[0]);\r
+ repair.Deck = deck;\r
+ return;\r
}\r
if (repair.DeckChanged(deck))\r
{\r
- _start = DateTime.MinValue;\r
- repair.Invalidate();\r
+ repair.State = State.Reset;\r
+ repair.Deck = deck;\r
}\r
- repair.Deck = deck.ToArray();\r
- var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\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 false;\r
- }\r
- if (totalHp == repair.TotalHp)\r
- return true;\r
- if (port && repair.TotalHp > 0 && totalHp != repair.TotalHp)\r
- _start = DateTime.MinValue;\r
+ var target = RepairTarget(deck);\r
+ if (repair.IsRepaired(target))\r
+ repair.State = State.Reset;\r
repair.UpdateTarget(target);\r
- return true;\r
}\r
\r
- private bool IsRepairable(int id)\r
+ private ShipStatus[] RepairTarget(int[] deck)\r
{\r
- var s = _shipInfo[id];\r
- return !_dockInfo.InNDock(id) && s.NowHp < s.MaxHp && s.DamageLevel < ShipStatus.Damage.Half;\r
+ var fs = _shipInfo.GetStatus(deck[0]);\r
+ if (!fs.Spec.IsRepairShip || _dockInfo.InNDock(fs.Id) || fs.DamageLevel >= ShipStatus.Damage.Half)\r
+ return new ShipStatus[0];\r
+ var cap = fs.Slot.Count(item => item.Spec.IsRepairFacility) + 2;\r
+ /*\r
+ * 泊地修理の条件を満たさない艦はMaxHp==NowHpのダミーを設定する。\r
+ * - 入渠中の艦娘は終わったときに回復扱いされないようNowHp=MaxHpに\r
+ * - 中破以上でNowHp=MaxHpにすると回復扱いされるのでNowHp=MaxHp=0に\r
+ */\r
+ return (from id in deck.Take(cap)\r
+ let s = (ShipStatus)_shipInfo.GetStatus(id).Clone()\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
}\r
\r
public RepairSpan[] GetTimers(int fleet)\r
+ => _start == DateTime.MinValue ? new RepairSpan[0] : _repairStatuses[fleet].GetTimers(_start, DateTime.Now);\r
+\r
+ public TimeSpan PresetDeckTimer\r
{\r
- if (_start == DateTime.MinValue)\r
- return new RepairSpan[0];\r
- return _repairStatuses[fleet].GetTimers(_start, DateTime.Now);\r
+ get\r
+ {\r
+ if (_start == DateTime.MinValue)\r
+ return TimeSpan.MinValue;\r
+ var r = TimeSpan.FromMinutes(20) - TimeSpan.FromSeconds((int)(DateTime.Now - _start).TotalSeconds);\r
+ return r >= TimeSpan.Zero ? r : TimeSpan.Zero;\r
+ }\r
}\r
\r
- public string[] GetNotice()\r
+ public bool CheckReparing(int fleet) => GetTimers(fleet).Any(r => r.Span != TimeSpan.MinValue);\r
+\r
+ public bool CheckReparing() => Enumerable.Range(0, ShipInfo.FleetCount).Any(CheckReparing);\r
+\r
+ public bool CheckPresetReparing()\r
+ => _shipInfo.PresetDeck.Where(deck => deck != null)\r
+ .Any(deck => RepairTarget(deck).Any(s => s.NowHp < s.MaxHp));\r
+\r
+ public Notice[] GetNotice()\r
{\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
+ return new Notice[0];\r
+ var r = _repairStatuses.Select(repair => repair.GetNotice(_start, prev, now)).ToArray();\r
+ var m20 = TimeSpan.FromMinutes(20);\r
+ if (prev - _start < m20 && now - _start >= m20)\r
+ r[0].Proceeded = "20分経過しました。";\r
+ return r;\r
}\r
}\r
}
\ No newline at end of file