OSDN Git Service

任務カウンターを実装する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Sniffer.cs
1 // Copyright (C) 2013, 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 // \r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.Collections.Generic;\r
17 using System.Globalization;\r
18 using System.Linq;\r
19 \r
20 namespace KancolleSniffer\r
21 {\r
22     public class Sniffer\r
23     {\r
24         private bool _start;\r
25         private readonly ItemInfo _itemInfo = new ItemInfo();\r
26         private readonly MaterialInfo _materialInfo = new MaterialInfo();\r
27         private readonly QuestInfo _questInfo;\r
28         private readonly MissionInfo _missionInfo = new MissionInfo();\r
29         private readonly ShipInfo _shipInfo;\r
30         private readonly ConditionTimer _conditionTimer;\r
31         private readonly DockInfo _dockInfo;\r
32         private readonly AkashiTimer _akashiTimer;\r
33         private readonly Achievement _achievement = new Achievement();\r
34         private readonly BattleInfo _battleInfo;\r
35         private readonly Logger _logger;\r
36         private readonly ExMapInfo _exMapInfo = new ExMapInfo();\r
37         private readonly MiscTextInfo _miscTextInfo = new MiscTextInfo();\r
38         private readonly BaseAirCoprs _baseAirCoprs;\r
39         private readonly PresetDeck _presetDeck = new PresetDeck();\r
40         private readonly Status _status = new Status();\r
41         private bool _saveState;\r
42         private readonly List<IHaveState> _haveState;\r
43 \r
44         public interface IRepeatingTimerController\r
45         {\r
46             void Stop(string key);\r
47             void Stop(string key, int fleet);\r
48             void Suspend();\r
49             void Resume();\r
50         }\r
51 \r
52         public IRepeatingTimerController RepeatingTimerController { get; set; }\r
53 \r
54         [Flags]\r
55         public enum Update\r
56         {\r
57             None = 0,\r
58             Error = 1 << 0,\r
59             Start = 1 << 1,\r
60             Item = 1 << 2,\r
61             Ship = 1 << 3,\r
62             Timer = 1 << 4,\r
63             NDock = 1 << 5,\r
64             Mission = 1 << 6,\r
65             QuestList = 1 << 7,\r
66             Battle = 1 << 8,\r
67             All = (1 << 9) - 1\r
68         }\r
69 \r
70         public Sniffer(bool start = false)\r
71         {\r
72             _start = start;\r
73             _shipInfo = new ShipInfo(_itemInfo);\r
74             _conditionTimer = new ConditionTimer(_shipInfo);\r
75             _dockInfo = new DockInfo(_shipInfo, _materialInfo);\r
76             _akashiTimer = new AkashiTimer(_shipInfo, _dockInfo, _presetDeck);\r
77             _battleInfo = new BattleInfo(_shipInfo, _itemInfo);\r
78             _logger = new Logger(_shipInfo, _itemInfo, _battleInfo);\r
79             _questInfo = new QuestInfo(_itemInfo, _battleInfo);\r
80             _baseAirCoprs = new BaseAirCoprs(_itemInfo);\r
81             _haveState = new List<IHaveState> {_achievement, _materialInfo, _conditionTimer, _exMapInfo, _questInfo};\r
82         }\r
83 \r
84         private void SaveState()\r
85         {\r
86             if (!_saveState)\r
87                 return;\r
88             if (!_haveState.Any(x => x.NeedSave))\r
89                 return;\r
90             foreach (var x in _haveState)\r
91                 x.SaveState(_status);\r
92             _status.Save();\r
93         }\r
94 \r
95         public void LoadState()\r
96         {\r
97             _status.Load();\r
98             foreach (var x in _haveState)\r
99                 x.LoadState(_status);\r
100             _saveState = true;\r
101         }\r
102 \r
103         public Update Sniff(string url, string request, dynamic json)\r
104         {\r
105             if (!json.api_result())\r
106                 return Update.Error;\r
107             if ((int)json.api_result != 1)\r
108                 return Update.None;\r
109             var data = json.api_data() ? json.api_data : new object();\r
110 \r
111             if (url.EndsWith("api_start2"))\r
112             {\r
113                 return ApiStart(data);\r
114             }\r
115             if (!_start)\r
116                 return Update.None;\r
117 \r
118             if (url.EndsWith("api_port/port"))\r
119                 return ApiPort(data);\r
120             if (url.Contains("member"))\r
121                 return ApiMember(url, json);\r
122             if (url.Contains("kousyou"))\r
123                 return ApiKousyou(url, request, data);\r
124             if (url.Contains("battle") || url.Contains("sortie"))\r
125                 return ApiBattle(url, request, data);\r
126             return ApiOthers(url, request, data);\r
127         }\r
128 \r
129         private Update ApiStart(dynamic data)\r
130         {\r
131             _shipInfo.InspectMaster(data);\r
132             _missionInfo.InspectMaster(data.api_mst_mission);\r
133             _itemInfo.InspectMaster(data);\r
134             _exMapInfo.ResetIfNeeded();\r
135             _start = true;\r
136             return Update.Start;\r
137         }\r
138 \r
139         private Update ApiPort(dynamic data)\r
140         {\r
141             _itemInfo.InspectBasic(data.api_basic);\r
142             _materialInfo.InspectMaterialPort(data.api_material);\r
143             _logger.InspectBasic(data.api_basic);\r
144             _logger.InspectMaterial(data.api_material);\r
145             _shipInfo.InspectShip(data);\r
146             _shipInfo.ClearBadlyDamagedShips();\r
147             _conditionTimer.CalcRegenTime();\r
148             _missionInfo.InspectDeck(data.api_deck_port);\r
149             _questInfo.InspectDeck(data.api_deck_port);\r
150             _dockInfo.InspectNDock(data.api_ndock);\r
151             _akashiTimer.Port();\r
152             _achievement.InspectBasic(data.api_basic);\r
153             if (data.api_parallel_quest_count()) // 昔のログにはないので\r
154                 _questInfo.AcceptMax = (int)data.api_parallel_quest_count;\r
155             if (data.api_event_object())\r
156                 _baseAirCoprs.InspectEventObject(data.api_event_object);\r
157             if (data.api_plane_info())\r
158                 _baseAirCoprs.InspectPlaneInfo(data.api_plane_info);\r
159             _battleInfo.CleanupResult();\r
160             _battleInfo.BattleState = BattleState.None;\r
161             _shipInfo.ClearEscapedShips();\r
162             _miscTextInfo.ClearIfNeeded();\r
163             SaveState();\r
164             RepeatingTimerController?.Resume();\r
165             foreach (var s in new[] {"遠征終了", "入渠終了", "疲労回復", "泊地修理"})\r
166                 RepeatingTimerController?.Stop(s);\r
167             return Update.All;\r
168         }\r
169 \r
170         private Update ApiMember(string url, dynamic json)\r
171         {\r
172             var data = json.api_data() ? json.api_data : new object();\r
173 \r
174             if (url.EndsWith("api_get_member/require_info"))\r
175             {\r
176                 _itemInfo.InspectSlotItem(data.api_slot_item, true);\r
177                 _dockInfo.InspectKDock(data.api_kdock);\r
178                 return Update.Timer;\r
179             }\r
180             if (url.EndsWith("api_get_member/basic"))\r
181             {\r
182                 _itemInfo.InspectBasic(data);\r
183                 _logger.InspectBasic(data);\r
184                 return Update.None;\r
185             }\r
186             if (url.EndsWith("api_get_member/slot_item"))\r
187             {\r
188                 _itemInfo.InspectSlotItem(data, true);\r
189                 return Update.Item;\r
190             }\r
191             if (url.EndsWith("api_get_member/kdock"))\r
192             {\r
193                 _dockInfo.InspectKDock(data);\r
194                 _logger.InspectKDock(data);\r
195                 return Update.Timer;\r
196             }\r
197             if (url.EndsWith("api_get_member/ndock"))\r
198             {\r
199                 _dockInfo.InspectNDock(data);\r
200                 _conditionTimer.CheckCond();\r
201                 _akashiTimer.CheckFleet();\r
202                 RepeatingTimerController?.Stop("入渠終了");\r
203                 return Update.NDock | Update.Timer | Update.Ship;\r
204             }\r
205             if (url.EndsWith("api_get_member/questlist"))\r
206             {\r
207                 _questInfo.InspectQuestList(data);\r
208                 return Update.QuestList;\r
209             }\r
210             if (url.EndsWith("api_get_member/deck"))\r
211             {\r
212                 _shipInfo.InspectDeck(data);\r
213                 _missionInfo.InspectDeck(data);\r
214                 _akashiTimer.CheckFleet();\r
215                 _questInfo.InspectDeck(data);\r
216                 return Update.Mission | Update.Timer;\r
217             }\r
218             if (url.EndsWith("api_get_member/ship2"))\r
219             {\r
220                 // ここだけjsonなので注意\r
221                 _shipInfo.InspectShip(json);\r
222                 _akashiTimer.CheckFleet();\r
223                 _battleInfo.BattleState = BattleState.None;\r
224                 return Update.Item | Update.Ship | Update.Battle;\r
225             }\r
226             if (url.EndsWith("api_get_member/ship_deck"))\r
227             {\r
228                 _shipInfo.InspectShip(data);\r
229                 _akashiTimer.CheckFleet();\r
230                 _battleInfo.BattleState = BattleState.None;\r
231                 return Update.Ship | Update.Battle;\r
232             }\r
233             if (url.EndsWith("api_get_member/ship3"))\r
234             {\r
235                 _shipInfo.InspectShip(data);\r
236                 _akashiTimer.CheckFleet();\r
237                 _conditionTimer.CheckCond();\r
238                 return Update.Ship;\r
239             }\r
240             if (url.EndsWith("api_get_member/material"))\r
241             {\r
242                 _materialInfo.InspectMaterial(data);\r
243                 return Update.Item;\r
244             }\r
245             if (url.EndsWith("api_get_member/mapinfo"))\r
246             {\r
247                 _exMapInfo.InspectMapInfo(data);\r
248                 _miscTextInfo.InspectMapInfo(data);\r
249                 if (data.api_air_base())\r
250                     _baseAirCoprs.Inspect(data.api_air_base);\r
251                 return Update.Item;\r
252             }\r
253             if (url.EndsWith("api_req_member/get_practice_enemyinfo"))\r
254             {\r
255                 _miscTextInfo.InspectPracticeEnemyInfo(data);\r
256                 return Update.Item;\r
257             }\r
258             if (url.EndsWith("api_get_member/preset_deck"))\r
259             {\r
260                 _presetDeck.Inspect(data);\r
261                 return Update.None;\r
262             }\r
263             if (url.EndsWith("api_get_member/base_air_corps"))\r
264             {\r
265                 _baseAirCoprs.Inspect(data);\r
266                 return Update.Ship;\r
267             }\r
268             return Update.None;\r
269         }\r
270 \r
271         private Update ApiKousyou(string url, string request, dynamic data)\r
272         {\r
273             if (url.EndsWith("api_req_kousyou/createitem"))\r
274             {\r
275                 _itemInfo.InspectCreateItem(data);\r
276                 _materialInfo.InspectCreateIem(data);\r
277                 _logger.InspectCreateItem(request, data);\r
278                 _questInfo.CountCreateItem();\r
279                 return Update.Item | Update.QuestList;\r
280             }\r
281             if (url.EndsWith("api_req_kousyou/getship"))\r
282             {\r
283                 _itemInfo.InspectGetShip(data);\r
284                 _shipInfo.InspectShip(data);\r
285                 _dockInfo.InspectKDock(data.api_kdock);\r
286                 _conditionTimer.CheckCond();\r
287                 RepeatingTimerController?.Stop("建造完了");\r
288                 return Update.Item | Update.Timer;\r
289             }\r
290             if (url.EndsWith("api_req_kousyou/destroyship"))\r
291             {\r
292                 _shipInfo.InspectDestroyShip(request, data);\r
293                 _materialInfo.InspectDestroyShip(data);\r
294                 _conditionTimer.CheckCond();\r
295                 _akashiTimer.CheckFleet();\r
296                 _questInfo.InspectDestroyShip(request);\r
297                 return Update.Item | Update.Ship | Update.QuestList;\r
298             }\r
299             if (url.EndsWith("api_req_kousyou/destroyitem2"))\r
300             {\r
301                 _questInfo.InspectDestroyItem(request, data); // 本当に削除される前\r
302                 _itemInfo.InspectDestroyItem(request, data);\r
303                 _materialInfo.InspectDestroyItem(data);\r
304                 return Update.Item | Update.QuestList;\r
305             }\r
306             if (url.EndsWith("api_req_kousyou/remodel_slot"))\r
307             {\r
308                 _logger.SetCurrentMaterial(_materialInfo.Current);\r
309                 _logger.InspectRemodelSlot(request, data); // 資材の差が必要なので_materialInfoより前\r
310                 _itemInfo.InspectRemodelSlot(data);\r
311                 _materialInfo.InspectRemodelSlot(data);\r
312                 _questInfo.CountRemodelSlot();\r
313                 return Update.Item | Update.QuestList;\r
314             }\r
315             if (url.EndsWith("api_req_kousyou/createship"))\r
316             {\r
317                 _logger.InspectCreateShip(request);\r
318                 _questInfo.CountCreateShip();\r
319                 return Update.QuestList;\r
320             }\r
321             if (url.EndsWith("api_req_kousyou/createship_speedchange"))\r
322             {\r
323                 _dockInfo.InspectCreateShipSpeedChange(request);\r
324                 return Update.Timer;\r
325             }\r
326             return Update.None;\r
327         }\r
328 \r
329         private Update ApiBattle(string url, string request, dynamic data)\r
330         {\r
331             if (IsNormalBattleAPI(url) || IsCombinedBattleAPI(url))\r
332             {\r
333                 _battleInfo.InspectBattle(url, request, data);\r
334                 _logger.InspectBattle(data);\r
335                 return Update.Ship | Update.Battle;\r
336             }\r
337             if (url.EndsWith("api_req_practice/battle") || url.EndsWith("api_req_practice/midnight_battle"))\r
338             {\r
339                 if (url.EndsWith("/battle"))\r
340                 {\r
341                     _shipInfo.InspectMapStart(request); // 演習を出撃中とみなす\r
342                     _conditionTimer.InvalidateCond();\r
343                     _miscTextInfo.ClearFlag = true;\r
344                     RepeatingTimerController?.Suspend();\r
345                 }\r
346                 _battleInfo.InspectBattle(url, request, data);\r
347                 return Update.Ship | Update.Battle | Update.Timer;\r
348             }\r
349             if (url.EndsWith("api_req_sortie/battleresult") || url.EndsWith("api_req_combined_battle/battleresult"))\r
350             {\r
351                 _battleInfo.InspectBattleResult(data);\r
352                 _exMapInfo.InspectBattleResult(data);\r
353                 _logger.InspectBattleResult(data);\r
354                 _questInfo.InspectBattleResult(data);\r
355                 return Update.Ship | Update.QuestList;\r
356             }\r
357             if (url.EndsWith("api_req_practice/battle_result"))\r
358             {\r
359                 _battleInfo.InspectPracticeResult(data);\r
360                 _questInfo.InspectPracticeResult(data);\r
361                 return Update.Ship | Update.QuestList;\r
362             }\r
363             if (url.EndsWith("/goback_port"))\r
364             {\r
365                 _battleInfo.CauseEscape();\r
366                 return Update.Ship;\r
367             }\r
368             _battleInfo.BattleState = BattleState.Unknown;\r
369             return Update.None;\r
370         }\r
371 \r
372         private bool IsNormalBattleAPI(string url)\r
373         {\r
374             return url.EndsWith("api_req_sortie/battle") ||\r
375                    url.EndsWith("api_req_sortie/airbattle") ||\r
376                    url.EndsWith("api_req_sortie/ld_airbattle") ||\r
377                    url.EndsWith("api_req_battle_midnight/battle") ||\r
378                    url.EndsWith("api_req_battle_midnight/sp_midnight");\r
379         }\r
380 \r
381         private bool IsCombinedBattleAPI(string url)\r
382         {\r
383             return url.EndsWith("api_req_combined_battle/battle") ||\r
384                    url.EndsWith("api_req_combined_battle/airbattle") ||\r
385                    url.EndsWith("api_req_combined_battle/ld_airbattle") ||\r
386                    url.EndsWith("api_req_combined_battle/battle_water") ||\r
387                    url.EndsWith("api_req_combined_battle/midnight_battle") ||\r
388                    url.EndsWith("api_req_combined_battle/sp_midnight") ||\r
389                    url.EndsWith("api_req_combined_battle/ec_battle") ||\r
390                    url.EndsWith("api_req_combined_battle/ec_midnight_battle") ||\r
391                    url.EndsWith("api_req_combined_battle/ec_night_to_day") ||\r
392                    url.EndsWith("api_req_combined_battle/each_battle") ||\r
393                    url.EndsWith("api_req_combined_battle/each_battle_water");\r
394         }\r
395 \r
396         private Update ApiOthers(string url, string request, dynamic data)\r
397         {\r
398             if (url.EndsWith("api_req_hensei/change"))\r
399             {\r
400                 _shipInfo.InspectChange(request);\r
401                 _akashiTimer.InspectChange(request);\r
402                 return Update.Ship;\r
403             }\r
404             if (url.EndsWith("api_req_hensei/preset_select"))\r
405             {\r
406                 _shipInfo.InspectDeck(new[] {data});\r
407                 _akashiTimer.CheckFleet();\r
408                 return Update.Ship;\r
409             }\r
410             if (url.EndsWith("api_req_hensei/preset_register"))\r
411             {\r
412                 _presetDeck.InspectRegister(data);\r
413                 return Update.None;\r
414             }\r
415             if (url.EndsWith("api_req_hensei/preset_delete"))\r
416             {\r
417                 _presetDeck.InspectDelete(request);\r
418                 return Update.Timer;\r
419             }\r
420             if (url.EndsWith("api_req_hensei/combined"))\r
421             {\r
422                 _shipInfo.InspectCombined(request);\r
423                 return Update.Ship;\r
424             }\r
425             if (url.EndsWith("api_req_hokyu/charge"))\r
426             {\r
427                 _shipInfo.InspectCharge(data);\r
428                 _materialInfo.InspectCharge(data);\r
429                 _questInfo.CountCharge();\r
430                 return Update.Item | Update.Ship | Update.QuestList;\r
431             }\r
432             if (url.EndsWith("api_req_kaisou/powerup"))\r
433             {\r
434                 _shipInfo.InspectPowerup(request, data);\r
435                 _conditionTimer.CheckCond();\r
436                 _akashiTimer.CheckFleet();\r
437                 _questInfo.InspectPowerup(data);\r
438                 return Update.Item | Update.Ship | Update.QuestList;\r
439             }\r
440             if (url.EndsWith("api_req_kaisou/slot_exchange_index"))\r
441             {\r
442                 _shipInfo.InspectSlotExchange(request, data);\r
443                 return Update.Ship;\r
444             }\r
445             if (url.EndsWith("api_req_kaisou/slot_deprive"))\r
446             {\r
447                 _shipInfo.InspectSlotDeprive(data);\r
448                 return Update.Ship;\r
449             }\r
450             if (url.EndsWith("api_req_nyukyo/start"))\r
451             {\r
452                 _dockInfo.InspectNyukyo(request);\r
453                 _conditionTimer.CheckCond();\r
454                 _akashiTimer.CheckFleet();\r
455                 _questInfo.CountNyukyo();\r
456                 var ndock = HttpUtility.ParseQueryString(request)["api_ndock_id"];\r
457                 if (ndock != null && int.TryParse(ndock, out int id))\r
458                     RepeatingTimerController?.Stop("入渠終了", id - 1);\r
459                 return Update.Item | Update.Ship | Update.QuestList;\r
460             }\r
461             if (url.EndsWith("api_req_nyukyo/speedchange"))\r
462             {\r
463                 _dockInfo.InspectSpeedChange(request);\r
464                 _conditionTimer.CheckCond();\r
465                 return Update.NDock | Update.Timer | Update.Item | Update.Ship;\r
466             }\r
467             if (url.EndsWith("api_req_map/start"))\r
468             {\r
469                 _shipInfo.InspectMapStart(request); // 出撃中判定が必要なので_conditionTimerより前\r
470                 _conditionTimer.InvalidateCond();\r
471                 _exMapInfo.InspectMapStart(data);\r
472                 _battleInfo.InspectMapStart(data);\r
473                 _logger.InspectMapStart(data);\r
474                 _miscTextInfo.ClearFlag = true;\r
475                 _questInfo.InspectMapStart(data);\r
476                 RepeatingTimerController?.Suspend();\r
477                 return Update.Timer | Update.Ship;\r
478             }\r
479             if (url.EndsWith("api_req_map/next"))\r
480             {\r
481                 _exMapInfo.InspectMapNext(data);\r
482                 _battleInfo.InspectMapNext(data);\r
483                 _logger.InspectMapNext(data);\r
484                 _questInfo.InspectMapNext(data);\r
485                 return Update.None;\r
486             }\r
487             if (url.EndsWith("api_req_mission/start"))\r
488             {\r
489                 var deck = HttpUtility.ParseQueryString(request)["api_deck_id"];\r
490                 if (deck != null && int.TryParse(deck, out int id))\r
491                     RepeatingTimerController?.Stop("遠征終了", id - 1);\r
492                 return Update.None;\r
493             }\r
494             if (url.EndsWith("api_req_mission/result"))\r
495             {\r
496                 _materialInfo.InspectMissionResult(data);\r
497                 _logger.InspectMissionResult(data);\r
498                 _questInfo.InspectMissionResult(request, data);\r
499                 return Update.Item;\r
500             }\r
501             if (url.EndsWith("api_req_quest/stop"))\r
502             {\r
503                 _questInfo.InspectStop(request);\r
504                 return Update.QuestList;\r
505             }\r
506             if (url.EndsWith("api_req_quest/clearitemget"))\r
507             {\r
508                 _questInfo.InspectClearItemGet(request);\r
509                 _logger.InspectClearItemGet(data);\r
510                 return Update.QuestList;\r
511             }\r
512             if (url.EndsWith("api_req_air_corps/supply"))\r
513             {\r
514                 _materialInfo.InspectAirCorpsSupply(data);\r
515                 _baseAirCoprs.InspectSupply(request, data);\r
516                 return Update.Item;\r
517             }\r
518             if (url.EndsWith("api_req_air_corps/set_plane"))\r
519             {\r
520                 _materialInfo.InspectAirCorpsSetPlane(data);\r
521                 _baseAirCoprs.InspectSetPlane(request, data);\r
522                 return Update.Item | Update.Ship;\r
523             }\r
524             if (url.EndsWith("api_req_air_corps/set_action"))\r
525             {\r
526                 _baseAirCoprs.InspectSetAction(request);\r
527                 return Update.Ship;\r
528             }\r
529             if (url.EndsWith("api_req_air_corps/expand_base"))\r
530             {\r
531                 _baseAirCoprs.InspectExpandBase(request, data);\r
532                 return Update.Ship;\r
533             }\r
534             return Update.None;\r
535         }\r
536 \r
537         public NameAndTimer[] NDock => _dockInfo.NDock;\r
538 \r
539         public RingTimer[] KDock => _dockInfo.KDock;\r
540 \r
541         public ItemInfo Item => _itemInfo;\r
542 \r
543         public MaterialInfo Material => _materialInfo;\r
544 \r
545         public QuestStatus[] Quests => _questInfo.Quests;\r
546 \r
547         public NameAndTimer[] Missions => _missionInfo.Missions;\r
548 \r
549         public DateTime GetConditionTimer(int fleet) => _conditionTimer.GetTimer(fleet);\r
550 \r
551         public int[] GetConditionNotice(DateTime prev, DateTime now) => _conditionTimer.GetNotice(prev, now);\r
552 \r
553         public ShipStatus[] GetShipStatuses(int fleet) => _shipInfo.GetShipStatuses(fleet);\r
554 \r
555         public int[] GetDeck(int fleet) => _shipInfo.GetDeck(fleet);\r
556 \r
557         public ShipInfo.ShipStatusPair[] BattleResultStatusDiff => _shipInfo.BattleResultDiff;\r
558 \r
559         public bool IsBattleResultStatusError => _shipInfo.IsBattleResultError;\r
560 \r
561         public ShipStatus[] BattleStartStatus => _shipInfo.BattleStartStatus;\r
562 \r
563         public int CombinedFleetType => _shipInfo.CombinedFleetType;\r
564 \r
565         public ChargeStatus[] ChargeStatuses => _shipInfo.ChargeStatuses;\r
566 \r
567         public int[] GetFighterPower(int fleet) => _shipInfo.GetFighterPower(fleet);\r
568 \r
569         public double GetContactTriggerRate(int fleet) => _shipInfo.GetContactTriggerRate(fleet);\r
570 \r
571         public double GetFleetLineOfSights(int fleet, int factor) => _shipInfo.GetLineOfSights(fleet, factor);\r
572 \r
573         public ShipStatus[] RepairList => _shipInfo.GetRepairList(_dockInfo);\r
574 \r
575         public ShipStatus[] ShipList => _shipInfo.ShipList;\r
576 \r
577         public string[] BadlyDamagedShips => _shipInfo.BadlyDamagedShips;\r
578 \r
579         public double GetDaihatsuBonus(int fleet) => _shipInfo.GetDaihatsuBonus(fleet);\r
580 \r
581         public double GetTransportPoint(int fleet) => _shipInfo.GetTransportPoint(fleet);\r
582 \r
583         public ItemStatus[] ItemList\r
584         {\r
585             get\r
586             {\r
587                 _itemInfo.ClearHolder();\r
588                 _shipInfo.SetItemHolder();\r
589                 _baseAirCoprs.SetItemHolder();\r
590                 return _itemInfo.ItemList;\r
591             }\r
592         }\r
593 \r
594         public AkashiTimer AkashiTimer => _akashiTimer;\r
595 \r
596         public Achievement Achievement => _achievement;\r
597 \r
598         public BattleInfo Battle => _battleInfo;\r
599 \r
600         public ExMapInfo ExMap => _exMapInfo;\r
601 \r
602         public string MiscText => _miscTextInfo.Text;\r
603 \r
604         public BaseAirCoprs.BaseInfo[] BaseAirCorps => _baseAirCoprs.AllAirCorps;\r
605 \r
606         public bool UseOldEnemyId\r
607         {\r
608             set => _shipInfo.UseOldEnemyId = value;\r
609         }\r
610 \r
611         public void SetLogWriter(Action<string, string, string> writer, Func<DateTime> nowFunc)\r
612         {\r
613             _logger.SetWriter(writer, nowFunc);\r
614         }\r
615 \r
616         public void SkipMaster()\r
617         {\r
618             _start = true;\r
619         }\r
620 \r
621         public void EnableLog(LogType type)\r
622         {\r
623             _logger.EnableLog(type);\r
624         }\r
625 \r
626         public int MaterialLogInterval\r
627         {\r
628             set => _logger.MaterialLogInterval = value;\r
629         }\r
630 \r
631         public string LogOutputDir\r
632         {\r
633             set => _logger.OutputDir = value;\r
634         }\r
635 \r
636         public void FlashLog()\r
637         {\r
638             _logger.FlashLog();\r
639         }\r
640     }\r
641 \r
642     public class NameAndTimer\r
643     {\r
644         public string Name { get; set; }\r
645         public RingTimer Timer { get; set; }\r
646 \r
647         public NameAndTimer()\r
648         {\r
649             Timer = new RingTimer();\r
650         }\r
651     }\r
652 \r
653     public class RingTimer\r
654     {\r
655         private readonly TimeSpan _spare;\r
656         private bool _finished;\r
657 \r
658         public bool IsFinished(DateTime now) => EndTime != DateTime.MinValue && EndTime - now < _spare || _finished;\r
659 \r
660         public DateTime EndTime { get; private set; }\r
661 \r
662         public RingTimer(int spare = 60)\r
663         {\r
664             _spare = TimeSpan.FromSeconds(spare);\r
665         }\r
666 \r
667         public void SetEndTime(double time)\r
668         {\r
669             SetEndTime((int)time == 0\r
670                 ? DateTime.MinValue\r
671                 : new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(time / 1000));\r
672         }\r
673 \r
674         public void SetEndTime(DateTime time)\r
675         {\r
676             EndTime = time;\r
677             _finished = false;\r
678         }\r
679 \r
680         public void Finish()\r
681         {\r
682             _finished = true;\r
683         }\r
684 \r
685         public bool CheckRing(DateTime prev, DateTime now)\r
686         {\r
687             return EndTime != DateTime.MinValue && prev != DateTime.MinValue &&\r
688                        prev < EndTime -_spare && EndTime - _spare <= now;\r
689         }\r
690 \r
691         public string ToString(DateTime now, bool endTime = false)\r
692         {\r
693             if (EndTime == DateTime.MinValue && !_finished)\r
694                 return "";\r
695             if (endTime)\r
696                 return EndTime.ToString(@"dd\ HH\:mm", CultureInfo.InvariantCulture);\r
697             var rest = _finished || EndTime - now < TimeSpan.Zero ? TimeSpan.Zero : EndTime - now;\r
698             return $"{(int)rest.TotalHours:d2}:" + rest.ToString(@"mm\:ss", CultureInfo.InvariantCulture);\r
699         }\r
700     }\r
701 }