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