OSDN Git Service

複数艦隊で泊地修理を行う際のタイマーを共通化する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / AkashiTimer.cs
1 // Copyright (C) 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
2 // \r
3 // This program is part of KancolleSniffer.\r
4 //\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify\r
6 // it under the terms of the GNU General Public License as published by\r
7 // the Free Software Foundation, either version 3 of the License, or\r
8 // (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 using System;\r
19 using System.Collections.Generic;\r
20 using System.Linq;\r
21 \r
22 namespace KancolleSniffer\r
23 {\r
24     public class AkashiTimer\r
25     {\r
26         private readonly ShipInfo _shipInfo;\r
27         private readonly ItemInfo _itemInfo;\r
28         private readonly DockInfo _dockInfo;\r
29         private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
30         private DateTime _start;\r
31         private DateTime _prev;\r
32 \r
33         public class RepairSpan\r
34         {\r
35             public int Diff { get; set; }\r
36             public TimeSpan Span { get; set; }\r
37 \r
38             public RepairSpan(int diff, TimeSpan span)\r
39             {\r
40                 Diff = diff;\r
41                 Span = span;\r
42             }\r
43         }\r
44 \r
45         private class RepairStatus\r
46         {\r
47             private ShipStatus[] _target = new ShipStatus[0];\r
48             private RepairSpan[][] _spans = new RepairSpan[0][];\r
49             private int[] _deck = new int[0];\r
50 \r
51             public int[] Deck\r
52             {\r
53                 set { _deck = value; }\r
54             }\r
55 \r
56             public void Invalidate()\r
57             {\r
58                 _target = new ShipStatus[0];\r
59                 _spans = new RepairSpan[0][];\r
60             }\r
61 \r
62             public int TotalHp\r
63             {\r
64                 get { return _target.Sum(s => s.NowHp); }\r
65             }\r
66 \r
67             public bool DeckChanged(IEnumerable<int> deck)\r
68             {\r
69                 return !_deck.SequenceEqual(deck);\r
70             }\r
71 \r
72             public void UpdateTarget(ShipStatus[] target)\r
73             {\r
74                 _target = target;\r
75                 CalcRepairSpan();\r
76             }\r
77 \r
78             private void CalcRepairSpan()\r
79             {\r
80                 _spans = (from s in _target\r
81                     let damage = s.MaxHp - s.NowHp\r
82                     let first = new RepairSpan(0, TimeSpan.FromMinutes(20))\r
83                     select damage == 0\r
84                         ? null\r
85                         : new[] {first}.Concat(from d in Enumerable.Range(2, damage < 2 ? 0 : damage - 1)\r
86                             let sec = s.CalcRepairSec(d) + 60\r
87                             where sec > 20 * 60\r
88                             select new RepairSpan(d - 1, TimeSpan.FromSeconds(sec))).ToArray()).ToArray();\r
89             }\r
90 \r
91             public RepairSpan[] GetTimers(DateTime start, DateTime now)\r
92             {\r
93                 var span = TimeSpan.FromSeconds((int)(now - start).TotalSeconds);\r
94                 return (from spans in _spans\r
95                     select spans == null\r
96                         ? new RepairSpan(0, TimeSpan.MinValue)\r
97                         : (from s in spans select new RepairSpan(s.Diff, s.Span - span))\r
98                             .FirstOrDefault(s => s.Span > TimeSpan.Zero)\r
99                           ?? new RepairSpan(spans.Last().Diff + 1, TimeSpan.Zero)\r
100                     ).ToArray();\r
101             }\r
102 \r
103             public string GetNotice(DateTime start, DateTime prev, DateTime now)\r
104             {\r
105                 var msg = string.Join(" ", from e in _spans.Zip(_target, (spans, ship) => new {spans, ship})\r
106                     where e.spans != null && e.spans.Any(\r
107                         s => s.Span - (prev - start) > TimeSpan.Zero && s.Span - (now - start) <= TimeSpan.Zero)\r
108                     select e.ship.Name);\r
109                 return msg == "" ? "" : "修理進行: " + msg;\r
110             }\r
111         }\r
112 \r
113         public AkashiTimer(ShipInfo ship, ItemInfo item, DockInfo dock)\r
114         {\r
115             _shipInfo = ship;\r
116             _itemInfo = item;\r
117             _dockInfo = dock;\r
118             for (var i = 0; i < _repairStatuses.Length; i++)\r
119                 _repairStatuses[i] = new RepairStatus();\r
120         }\r
121 \r
122         public void SetTimer(bool port = false)\r
123         {\r
124             var cont = false;\r
125             for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
126             {\r
127                 if (CheckFleet(fleet, port))\r
128                     cont = true;\r
129             }\r
130             if (!cont)\r
131             {\r
132                 _start = DateTime.MinValue;\r
133                 return;\r
134             }\r
135             if (_start == DateTime.MinValue)\r
136                 _start = DateTime.Now;\r
137         }\r
138 \r
139         private bool CheckFleet(int fleet, bool port)\r
140         {\r
141             var deck = _shipInfo.GetDeck(fleet);\r
142             var repair = _repairStatuses[fleet];\r
143             var fs = deck[0];\r
144             if (!_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) || _shipInfo.InMission(fleet))\r
145             {\r
146                 repair.Invalidate();\r
147                 return false;\r
148             }\r
149             if (repair.DeckChanged(deck))\r
150             {\r
151                 _start = DateTime.MinValue;\r
152                 repair.Invalidate();\r
153             }\r
154             repair.Deck = deck.ToArray();\r
155             var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\r
156             var target =\r
157                 (from id in deck.Take(cap) select IsRepairable(id) ? _shipInfo[id] : new ShipStatus()).ToArray();\r
158             var totalHp = target.Sum(s => s.NowHp);\r
159             if (totalHp == 0)\r
160             {\r
161                 repair.Invalidate();\r
162                 return false;\r
163             }\r
164             if (totalHp == repair.TotalHp)\r
165                 return true;\r
166             if (port && repair.TotalHp > 0 && totalHp != repair.TotalHp)\r
167                 _start = DateTime.MinValue;\r
168             repair.UpdateTarget(target);\r
169             return true;\r
170         }\r
171 \r
172         private bool IsRepairable(int id)\r
173         {\r
174             var s = _shipInfo[id];\r
175             return !_dockInfo.InNDock(id) && s.NowHp < s.MaxHp && s.DamageLevel < ShipStatus.Damage.Half;\r
176         }\r
177 \r
178         public RepairSpan[] GetTimers(int fleet)\r
179         {\r
180             if (_start == DateTime.MinValue)\r
181                 return new RepairSpan[0];\r
182             return _repairStatuses[fleet].GetTimers(_start, DateTime.Now);\r
183         }\r
184 \r
185         public string[] GetNotice()\r
186         {\r
187             var now = DateTime.Now;\r
188             var prev = _prev;\r
189             _prev = now;\r
190             if (prev == DateTime.MinValue || _start == DateTime.MinValue)\r
191                 return new string[0];\r
192             if (prev - _start < TimeSpan.FromMinutes(20) && now - _start >= TimeSpan.FromMinutes(20))\r
193                 return new[] {"20分経過しました。"};\r
194             return _repairStatuses.Select(repair => repair.GetNotice(_start, prev, now)).ToArray();\r
195         }\r
196     }\r
197 }