OSDN Git Service

idが-1かどうかの場合分けを減らすリファクタリング
[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.Linq;\r
20 \r
21 namespace KancolleSniffer\r
22 {\r
23     public class AkashiTimer\r
24     {\r
25         private readonly ShipInfo _shipInfo;\r
26         private readonly ItemInfo _itemInfo;\r
27         private readonly DockInfo _dockInfo;\r
28         private readonly MissionInfo _missionInfo;\r
29         private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
30 \r
31         private struct RepairStatus\r
32         {\r
33             public DateTime Timer { get; set; }\r
34             public int TotalHp { get; set; }\r
35             public int[] Deck { private get; set; }\r
36 \r
37             public void Invalidate()\r
38             {\r
39                 Timer = DateTime.MinValue;\r
40                 TotalHp = 0;\r
41                 Deck = null;\r
42             }\r
43 \r
44             public bool DeckChanged(int[] deck)\r
45             {\r
46                 return Deck != null && Deck.Where((t, i) => deck[i] != t).Any();\r
47             }\r
48         }\r
49 \r
50         public AkashiTimer(ShipInfo ship, ItemInfo item, DockInfo dock, MissionInfo mission)\r
51         {\r
52             _shipInfo = ship;\r
53             _itemInfo = item;\r
54             _dockInfo = dock;\r
55             _missionInfo = mission;\r
56         }\r
57 \r
58         public void SetTimer(bool port = false)\r
59         {\r
60             for (var fleet = 0; fleet < ShipInfo.FleetCount; fleet++)\r
61                 SetTimer(fleet, port);\r
62         }\r
63 \r
64         private void SetTimer(int fleet, bool port)\r
65         {\r
66             var deck = _shipInfo.GetDeck(fleet);\r
67             var fs = deck[0];\r
68             if (!_shipInfo[fs].Name.StartsWith("明石") || _dockInfo.InNDock(fs) || _missionInfo.InMission(fleet))\r
69             {\r
70                 InvalidateTimer(fleet);\r
71                 return;\r
72             }\r
73             if (_repairStatuses[fleet].DeckChanged(deck))\r
74                 InvalidateTimer(fleet);\r
75             var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\r
76             var targets = deck.Take(cap).Where(id => !_dockInfo.InNDock(id)).ToArray();\r
77             var totalHp = (from id in targets\r
78                 let status = _shipInfo[id]\r
79                 where status.NowHp < status.MaxHp && status.DamageLevel < ShipStatus.Damage.Half\r
80                 select status.NowHp).Sum();\r
81             if (totalHp == 0)\r
82             {\r
83                 InvalidateTimer(fleet);\r
84                 return;\r
85             }\r
86             var r = _repairStatuses[fleet];\r
87             if (r.TotalHp == totalHp)\r
88                 return;\r
89             var timer = r.Timer;\r
90             /*\r
91              * 母港に遷移したときに、耐久値が回復しているか修理開始から20分経過しているときに\r
92              * タイマーをリスタートする。\r
93              * \r
94              * Q. なぜ20分でリスタートするのか?\r
95              * \r
96              * A. 明石の修理は戦闘中も続くので、戦闘中に修理開始から20分経つと母港に戻った\r
97              *    ときに耐久値が回復する。最後の戦闘で損傷すると、損傷と回復が同時に耐久値に\r
98              *    反映されて回復が起こったことがわからない。耐久値の回復だけを基準にすると\r
99              *    リスタートできないので、20分経過していたらリスタートする。\r
100             */\r
101             if (timer == DateTime.MinValue ||\r
102                 (port && (totalHp > r.TotalHp || (DateTime.Now - timer).TotalMinutes > 20)))\r
103                 timer = DateTime.Now;\r
104             _repairStatuses[fleet] = new RepairStatus\r
105             {\r
106                 Timer = timer,\r
107                 TotalHp = totalHp,\r
108                 Deck = deck.ToArray()\r
109             };\r
110         }\r
111 \r
112         private void InvalidateTimer(int fleet)\r
113         {\r
114             _repairStatuses[fleet].Invalidate();\r
115         }\r
116 \r
117         public DateTime this[int fleet]\r
118         {\r
119             get { return _repairStatuses[fleet].Timer; }\r
120         }\r
121     }\r
122 }