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