OSDN Git Service

夜戦の突入時に大破警告を出さないようにする
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / BattleInfo.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 BattleInfo\r
25     {\r
26         private readonly ShipMaster _shipMaster;\r
27         private readonly ShipInfo _shipInfo;\r
28         private readonly ItemInfo _itemInfo;\r
29         private dynamic _day;\r
30         private dynamic _night;\r
31         private bool _isSurface;\r
32         private readonly List<int> _escapingShips = new List<int>();\r
33         public bool InBattle { get; set; }\r
34         public string Formation { get; private set; }\r
35         public int EnemyAirSuperiority { get; private set; }\r
36         public bool HasDamagedShip { get; set; }\r
37         public string[] DamagedShipNames { get; private set; }\r
38 \r
39         public BattleInfo(ShipMaster shipMaster, ShipInfo shipInfo, ItemInfo itemInfo)\r
40         {\r
41             _shipMaster = shipMaster;\r
42             _shipInfo = shipInfo;\r
43             _itemInfo = itemInfo;\r
44         }\r
45 \r
46         public void InspectBattle(dynamic json)\r
47         {\r
48             InBattle = true;\r
49             Formation = FormationName(json);\r
50             EnemyAirSuperiority = CalcEnemyAirSuperiority(json);\r
51             if (IsNightBattle(json))\r
52             {\r
53                 CauseDamage(false);\r
54                 _night = json;\r
55             }\r
56             else\r
57             {\r
58                 _day = json;\r
59             }\r
60         }\r
61 \r
62         public void InspectPracticeBattle(dynamic json)\r
63         {\r
64             InspectBattle(json);\r
65             HasDamagedShip = false;\r
66         }\r
67 \r
68         public void InspectCombinedBattle(dynamic json, bool surfaceFleet)\r
69         {\r
70             InBattle = true;\r
71             Formation = FormationName(json);\r
72             EnemyAirSuperiority = CalcEnemyAirSuperiority(json);\r
73             if (IsNightBattle(json))\r
74             {\r
75                 CauseDamageCombined(false);\r
76                 _night = json;\r
77             }\r
78             else\r
79             {\r
80                 _isSurface = surfaceFleet;\r
81                 _day = json;\r
82             }\r
83         }\r
84 \r
85         private bool IsNightBattle(dynamic json)\r
86         {\r
87             return json.api_hougeki();\r
88         }\r
89 \r
90         public void InspectCombinedBattleResult(dynamic json)\r
91         {\r
92             _escapingShips.Clear();\r
93             CauseDamageCombined();\r
94             if ((int)json.api_escape_flag == 0)\r
95                 return;\r
96             var damaged = (int)json.api_escape.api_escape_idx[0] - 1;\r
97             _escapingShips.Add(_shipInfo.GetDeck(damaged / 6)[damaged % 6]);\r
98             var escort = (int)json.api_escape.api_tow_idx[0] - 1;\r
99             _escapingShips.Add(_shipInfo.GetDeck(escort / 6)[escort % 6]);\r
100         }\r
101 \r
102         public void CauseCombinedBattleEscape()\r
103         {\r
104             _shipInfo.SetEscapedShips(_escapingShips);\r
105             UpdateDamgedShipNames(_shipInfo.GetShipStatuses(0).Concat(_shipInfo.GetShipStatuses(1)));\r
106         }\r
107 \r
108         private string FormationName(dynamic json)\r
109         {\r
110             if (!json.api_formation()) // 演習の夜戦\r
111                 return "";\r
112             switch ((int)json.api_formation[2])\r
113             {\r
114                 case 1:\r
115                     return "同航戦";\r
116                 case 2:\r
117                     return "反航戦";\r
118                 case 3:\r
119                     return "T字有利";\r
120                 case 4:\r
121                     return "T字不利";\r
122             }\r
123             return "";\r
124         }\r
125 \r
126         private int CalcEnemyAirSuperiority(dynamic json)\r
127         {\r
128             var maxEq = ((int[])json.api_ship_ke).Skip(1).SelectMany(id => _shipMaster[id].MaxEq);\r
129             var equips = ((int[][])json.api_eSlot).SelectMany(x => x);\r
130             return (from slot in equips.Zip(maxEq, (id, max) => new {id, max})\r
131                 let spec = _itemInfo.GetSpecByItemId(slot.id)\r
132                 where spec.CanAirCombat()\r
133                 select (int)Math.Floor(spec.AntiAir * Math.Sqrt(slot.max))).DefaultIfEmpty().Sum();\r
134         }\r
135 \r
136         public void CauseDamage(bool warnDamagedShip = true)\r
137         {\r
138             if (_day == null && _night == null)\r
139                 return;\r
140             var ships = _shipInfo.GetShipStatuses((int)DeckId(_day ?? _night));\r
141             if (_day != null)\r
142             {\r
143                 var json = _day;\r
144                 if (json.api_kouku.api_stage3 != null)\r
145                     CauseSimpleDamage(ships, json.api_kouku.api_stage3.api_fdam);\r
146                 if (json.api_opening_atack != null)\r
147                     CauseSimpleDamage(ships, json.api_opening_atack.api_fdam);\r
148                 if (json.api_hougeki1 != null)\r
149                     CauseHougekiDamage(ships, json.api_hougeki1);\r
150                 if (json.api_hougeki2 != null)\r
151                     CauseHougekiDamage(ships, json.api_hougeki2);\r
152                 if (json.api_raigeki != null)\r
153                     CauseSimpleDamage(ships, json.api_raigeki.api_fdam);\r
154                 _day = null;\r
155             }\r
156             if (_night != null)\r
157             {\r
158                 CauseHougekiDamage(ships, _night.api_hougeki);\r
159                 _night = null;\r
160             }\r
161             if (warnDamagedShip)\r
162                 UpdateDamgedShipNames(ships);\r
163         }\r
164 \r
165         public void CausePracticeDamage()\r
166         {\r
167             CauseDamage(false);\r
168         }\r
169 \r
170         private void UpdateDamgedShipNames(IEnumerable<ShipStatus> ships)\r
171         {\r
172             DamagedShipNames =\r
173                 (from ship in ships where ship.DamageLevel == ShipStatus.Damage.Badly select ship.Name).ToArray();\r
174             HasDamagedShip = DamagedShipNames.Any();\r
175         }\r
176 \r
177         private int DeckId(dynamic json)\r
178         {\r
179             if (json.api_dock_id()) // 昼戦はtypoしている\r
180                 return (int)json.api_dock_id - 1;\r
181             if (json.api_deck_id is string) // 通常の夜戦では文字列\r
182                 return int.Parse(json.api_deck_id) - 1;\r
183             return (int)json.api_deck_id - 1;\r
184         }\r
185 \r
186         private void CauseSimpleDamage(ShipStatus[] ships, dynamic rawDamage)\r
187         {\r
188             var damage = (int[])rawDamage;\r
189             for (var i = 0; i < ships.Length; i++)\r
190                 ships[i].NowHp -= damage[i + 1];\r
191         }\r
192 \r
193         private void CauseHougekiDamage(ShipStatus[] ships, dynamic hougeki)\r
194         {\r
195             var targets = ((dynamic[])hougeki.api_df_list).Skip(1).SelectMany(x => (int[])x);\r
196             var damages = ((dynamic[])hougeki.api_damage).Skip(1).SelectMany(x => (double[])x);\r
197             foreach (var hit in targets.Zip(damages, (t, d) => new {t, d}))\r
198             {\r
199                 if (1 <= hit.t && hit.t <= ships.Length)\r
200                     ships[hit.t - 1].NowHp -= (int)hit.d;\r
201             }\r
202         }\r
203 \r
204         public void CauseDamageCombined(bool warnDamagedShip = true)\r
205         {\r
206             if (_isSurface)\r
207                 CauseDamageCombinedFleetSurface(warnDamagedShip);\r
208             else\r
209                 CauseDamageCombinedFleetAir(warnDamagedShip);\r
210         }\r
211 \r
212         private void CauseDamageCombinedFleetAir(bool warnDamagedShip)\r
213         {\r
214             var hontai = _shipInfo.GetShipStatuses(0);\r
215             var goei = _shipInfo.GetShipStatuses(1);\r
216             if (_day != null)\r
217             {\r
218                 var json = _day;\r
219                 var kouku = json.api_kouku;\r
220                 if (kouku.api_stage3 != null)\r
221                     CauseSimpleDamage(hontai, kouku.api_stage3.api_fdam);\r
222                 if (kouku.api_stage3_combined != null)\r
223                     CauseSimpleDamage(goei, kouku.api_stage3_combined.api_fdam);\r
224                 if (json.api_kouku2()) // 航空戦2回目\r
225                 {\r
226                     kouku = json.api_kouku2;\r
227                     if (kouku.api_stage3 != null)\r
228                         CauseSimpleDamage(hontai, kouku.api_stage3.api_fdam);\r
229                     if (kouku.api_stage3_combined != null)\r
230                         CauseSimpleDamage(goei, kouku.api_stage3_combined.api_fdam);\r
231                 }\r
232                 if (!json.api_opening_atack()) // 航空戦のみ\r
233                     return;\r
234                 if (json.api_opening_atack != null)\r
235                     CauseSimpleDamage(goei, json.api_opening_atack.api_fdam);\r
236                 if (json.api_hougeki1 != null)\r
237                     CauseHougekiDamage(goei, json.api_hougeki1);\r
238                 if (json.api_hougeki2() && json.api_hougeki2 != null)\r
239                     CauseHougekiDamage(hontai, json.api_hougeki2);\r
240                 if (json.api_hougeki3() && json.api_hougeki3 != null)\r
241                     CauseHougekiDamage(hontai, json.api_hougeki3);\r
242                 if (json.api_raigeki() && json.api_raigeki != null)\r
243                     CauseSimpleDamage(goei, json.api_raigeki.api_fdam);\r
244                 _day = null;\r
245             }\r
246             if (_night != null)\r
247             {\r
248                 CauseHougekiDamage(goei, _night.api_hougeki);\r
249                 _night = null;\r
250             }\r
251             if (warnDamagedShip)\r
252                 UpdateDamgedShipNames(hontai.Concat(goei));\r
253         }\r
254 \r
255         private void CauseDamageCombinedFleetSurface(bool warnDamagedShip)\r
256         {\r
257             var hontai = _shipInfo.GetShipStatuses(0);\r
258             var goei = _shipInfo.GetShipStatuses(1);\r
259             if (_day != null)\r
260             {\r
261                 var json = _day;\r
262                 var kouku = json.api_kouku;\r
263                 if (kouku.api_stage3 != null)\r
264                     CauseSimpleDamage(hontai, kouku.api_stage3.api_fdam);\r
265                 if (kouku.api_stage3_combined != null)\r
266                     CauseSimpleDamage(goei, kouku.api_stage3_combined.api_fdam);\r
267                 if (json.api_opening_atack != null)\r
268                     CauseSimpleDamage(goei, json.api_opening_atack.api_fdam);\r
269                 if (json.api_hougeki1 != null)\r
270                     CauseHougekiDamage(hontai, json.api_hougeki1);\r
271                 if (json.api_hougeki2() && json.api_hougeki2 != null)\r
272                     CauseHougekiDamage(hontai, json.api_hougeki2);\r
273                 if (json.api_hougeki3() && json.api_hougeki3 != null)\r
274                     CauseHougekiDamage(goei, json.api_hougeki3);\r
275                 if (json.api_raigeki() && json.api_raigeki != null)\r
276                     CauseSimpleDamage(goei, json.api_raigeki.api_fdam);\r
277                 _day = null;\r
278             }\r
279             if (_night != null)\r
280             {\r
281                 CauseHougekiDamage(goei, _night.api_hougeki);\r
282                 _night = null;\r
283             }\r
284             if (warnDamagedShip)\r
285                 UpdateDamgedShipNames(hontai.Concat(goei));\r
286         }\r
287     }\r
288 }