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