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.Linq;\r
20 \r
21 namespace KancolleSniffer\r
22 {\r
23     public class BattleInfo\r
24     {\r
25         private readonly ShipMaster _shipMaster;\r
26         private readonly ShipInfo _shipInfo;\r
27         private readonly ItemInfo _itemInfo;\r
28         private dynamic _prevBattle;\r
29         private bool _isSurfaceFleet;\r
30         public bool InBattle { get; set; }\r
31         public string Formation { get; private set; }\r
32         public int EnemyAirSuperiority { get; private set; }\r
33         public bool HasDamagedShip { get; set; }\r
34         public string[] DamagedShipNames { get; private set; }\r
35 \r
36         public BattleInfo(ShipMaster shipMaster, ShipInfo shipInfo, ItemInfo itemInfo)\r
37         {\r
38             _shipMaster = shipMaster;\r
39             _shipInfo = shipInfo;\r
40             _itemInfo = itemInfo;\r
41         }\r
42 \r
43         public void InspectBattle(dynamic json)\r
44         {\r
45             InBattle = true;\r
46             Formation = FormationName(json);\r
47             EnemyAirSuperiority = CalcEnemyAirSuperiority(json);\r
48             _prevBattle = json;\r
49         }\r
50 \r
51         public void InspectCombinedBattle(dynamic json, bool surfaceFleet)\r
52         {\r
53             InBattle = true;\r
54             Formation = FormationName(json);\r
55             EnemyAirSuperiority = CalcEnemyAirSuperiority(json);\r
56             _prevBattle = json;\r
57             _isSurfaceFleet = surfaceFleet;\r
58         }\r
59 \r
60         private string FormationName(dynamic json)\r
61         {\r
62             if (!json.api_formation()) // 演習の夜戦\r
63                 return "";\r
64             switch ((int)json.api_formation[2])\r
65             {\r
66                 case 1:\r
67                     return "同航戦";\r
68                 case 2:\r
69                     return "反航戦";\r
70                 case 3:\r
71                     return "T字有利";\r
72                 case 4:\r
73                     return "T字不利";\r
74             }\r
75             return "";\r
76         }\r
77 \r
78         private int CalcEnemyAirSuperiority(dynamic json)\r
79         {\r
80             var maxEq = ((int[])json.api_ship_ke).Skip(1).SelectMany(id => _shipMaster[id].MaxEq);\r
81             var equips = ((int[][])json.api_eSlot).SelectMany(x => x);\r
82             return (from slot in equips.Zip(maxEq, (id, max) => new {id, max})\r
83                 let spec = _itemInfo.GetSpecByItemId(slot.id)\r
84                 where spec.CanAirCombat()\r
85                 select (int)Math.Floor(spec.AntiAir * Math.Sqrt(slot.max))).DefaultIfEmpty().Sum();\r
86         }\r
87 \r
88         public void CauseDamage()\r
89         {\r
90             var json = _prevBattle;\r
91             if (json == null)\r
92                 return;\r
93             var ships = _shipInfo.GetShipStatuses((int)DeckId(json));\r
94             if (json.api_hougeki()) // 夜戦\r
95             {\r
96                 CauseHougekiDamage(ships, json.api_hougeki);\r
97             }\r
98             else // 昼戦\r
99             {\r
100                 if (json.api_kouku.api_stage3 != null)\r
101                     CauseSimpleDamage(ships, json.api_kouku.api_stage3.api_fdam);\r
102                 if (json.api_opening_atack != null)\r
103                     CauseSimpleDamage(ships, json.api_opening_atack.api_fdam);\r
104                 if (json.api_hougeki1 != null)\r
105                     CauseHougekiDamage(ships, json.api_hougeki1);\r
106                 if (json.api_hougeki2 != null)\r
107                     CauseHougekiDamage(ships, json.api_hougeki2);\r
108                 if (json.api_raigeki != null)\r
109                     CauseSimpleDamage(ships, json.api_raigeki.api_fdam);\r
110             }\r
111             DamagedShipNames =\r
112                 (from ship in ships where ship.DamageLevel == ShipStatus.Damage.Badly select ship.Name).ToArray();\r
113             HasDamagedShip = DamagedShipNames.Any();\r
114         }\r
115 \r
116         private int DeckId(dynamic json)\r
117         {\r
118             return (int)(json.api_dock_id() ? json.api_dock_id : json.api_deck_id) - 1; // 昼戦はtypoをしている\r
119         }\r
120 \r
121         private void CauseSimpleDamage(ShipStatus[] ships, dynamic rawDamage)\r
122         {\r
123             var damage = (int[])rawDamage;\r
124             for (var i = 0; i < ships.Length; i++)\r
125                 ships[i].NowHp -= damage[i + 1];\r
126         }\r
127 \r
128         private void CauseHougekiDamage(ShipStatus[] ships, dynamic hougeki)\r
129         {\r
130             var targets = ((dynamic[])hougeki.api_df_list).Skip(1).SelectMany(x => (int[])x);\r
131             var damages = ((dynamic[])hougeki.api_damage).Skip(1).SelectMany(x => (double[])x);\r
132             foreach (var hit in targets.Zip(damages, (t, d) => new {t, d}))\r
133             {\r
134                 if (hit.t - 1 < ships.Length)\r
135                     ships[hit.t - 1].NowHp -= (int)hit.d;\r
136             }\r
137         }\r
138 \r
139         public void CauseDamageCombined()\r
140         {\r
141             if (_prevBattle == null)\r
142                 return;\r
143             var hontai = _shipInfo.GetShipStatuses(0);\r
144             var goei = _shipInfo.GetShipStatuses(1);\r
145             if (_isSurfaceFleet)\r
146                 CauseDamageCombinedSurfaceFleet(_prevBattle, hontai, goei);\r
147             else\r
148                 CauseDamageCombinedTaskFleet(_prevBattle, hontai, goei);\r
149             DamagedShipNames =\r
150                 (from ship in hontai.Concat(goei) where ship.DamageLevel == ShipStatus.Damage.Badly select ship.Name).ToArray();\r
151             HasDamagedShip = DamagedShipNames.Any();\r
152         }\r
153 \r
154         private void CauseDamageCombinedTaskFleet(dynamic json, ShipStatus[] hontai, ShipStatus[] goei)\r
155         {\r
156             bool midnight = json.api_hougeki();\r
157             if (midnight)\r
158             {\r
159                 CauseHougekiDamage(goei, json.api_hougeki);\r
160             }\r
161             else // 昼戦\r
162             {\r
163                 var kouku = json.api_kouku;\r
164                 if (kouku.api_stage3 != null)\r
165                     CauseSimpleDamage(hontai, kouku.api_stage3.api_fdam);\r
166                 if (kouku.api_stage3_combined != null)\r
167                     CauseSimpleDamage(goei, kouku.api_stage3_combined.api_fdam);\r
168                 if (json.api_kouku2()) // 航空戦2回目\r
169                 {\r
170                     kouku = json.api_kouku2;\r
171                     if (kouku.api_stage3 != null)\r
172                         CauseSimpleDamage(hontai, kouku.api_stage3.api_fdam);\r
173                     if (kouku.api_stage3_combined != null)\r
174                         CauseSimpleDamage(goei, kouku.api_stage3_combined.api_fdam);\r
175                 }\r
176                 if (!json.api_opening_atack()) // 航空戦のみ\r
177                     return;\r
178                 if (json.api_opening_atack != null)\r
179                     CauseSimpleDamage(goei, json.api_opening_atack.api_fdam);\r
180                 if (json.api_hougeki1 != null)\r
181                     CauseHougekiDamage(goei, json.api_hougeki1);\r
182                 if (json.api_hougeki2() && json.api_hougeki2 != null)\r
183                     CauseHougekiDamage(hontai, json.api_hougeki2);\r
184                 if (json.api_hougeki3() && json.api_hougeki3 != null)\r
185                     CauseHougekiDamage(hontai, json.api_hougeki3);\r
186                 if (json.api_raigeki() && json.api_raigeki != null)\r
187                     CauseSimpleDamage(goei, json.api_raigeki.api_fdam);\r
188             }\r
189         }\r
190 \r
191         private void CauseDamageCombinedSurfaceFleet(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_opening_atack != null)\r
206                     CauseSimpleDamage(goei, json.api_opening_atack.api_fdam);\r
207                 if (json.api_hougeki1 != null)\r
208                     CauseHougekiDamage(hontai, json.api_hougeki1);\r
209                 if (json.api_hougeki2() && json.api_hougeki2 != null)\r
210                     CauseHougekiDamage(hontai, json.api_hougeki2);\r
211                 if (json.api_hougeki3() && json.api_hougeki3 != null)\r
212                     CauseHougekiDamage(goei, json.api_hougeki3);\r
213                 if (json.api_raigeki() && json.api_raigeki != null)\r
214                     CauseSimpleDamage(goei, json.api_raigeki.api_fdam);\r
215             }\r
216         }\r
217     }\r
218 }