OSDN Git Service

装備を交換するAPIの仕様変更に対応する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Model / AirBase.cs
1 // Copyright (C) 2016 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.Collections.Generic;\r
17 using System.Collections.Specialized;\r
18 using System.Linq;\r
19 using KancolleSniffer.Util;\r
20 \r
21 namespace KancolleSniffer.Model\r
22 {\r
23     public class AirBase\r
24     {\r
25         private readonly ItemInfo _itemInfo;\r
26         private List<int> _relocatingPlanes = new List<int>();\r
27 \r
28         public AirBase(ItemInfo item)\r
29         {\r
30             _itemInfo = item;\r
31         }\r
32 \r
33         public BaseInfo[] AllAirCorps { get; set; }\r
34 \r
35         public class BaseInfo\r
36         {\r
37             public int AreaId { get; set; }\r
38             public string AreaName => AreaId == 6 ? "中部海域" : "限定海域";\r
39             public AirCorpsInfo[] AirCorps { get; set; }\r
40         }\r
41 \r
42         public class Distance\r
43         {\r
44             public int Base { get; set; }\r
45             public int Bonus { get; set; }\r
46 \r
47             public override string ToString() => Bonus > 0 ? $"{Base}+{Bonus}" : Base.ToString();\r
48         }\r
49 \r
50         public class AirCorpsInfo\r
51         {\r
52             public Distance Distance { get; set; }\r
53             public int Action { get; set; }\r
54             public PlaneInfo[] Planes { get; set; }\r
55 \r
56             public string ActionName\r
57             {\r
58                 get\r
59                 {\r
60                     switch (Action)\r
61                     {\r
62                         case 0:\r
63                             return "待機";\r
64                         case 1:\r
65                             return "出撃";\r
66                         case 2:\r
67                             return "防空";\r
68                         case 3:\r
69                             return "退避";\r
70                         case 4:\r
71                             return "休息";\r
72                         default:\r
73                             return "";\r
74                     }\r
75                 }\r
76             }\r
77 \r
78             public AirBaseParams[] CalcFighterPower()\r
79             {\r
80                 var reconPlaneBonus = Planes.Aggregate(new AirBaseParams(), (max, plane) =>\r
81                 {\r
82                     var bonus = plane.Slot.Spec.ReconPlaneAirBaseBonus;\r
83                     return AirBaseParams.Max(max, bonus);\r
84                 });\r
85                 return Planes.Aggregate(new[] {new AirBaseParams(), new AirBaseParams()}, (previous, plane) =>\r
86                 {\r
87                     if (plane.State != 1)\r
88                         return previous;\r
89                     var current = plane.Slot.CalcFighterPowerInBase(plane.Count);\r
90                     return new[]\r
91                     {\r
92                         previous[0] + current[0],\r
93                         previous[1] + current[1]\r
94                     };\r
95                 }).Select(param => (param * reconPlaneBonus).Floor()).ToArray();\r
96             }\r
97 \r
98             public int[] CostForSortie => Planes.Aggregate(new[] {0, 0}, (prev, plane) =>\r
99             {\r
100                 if (plane.State != 1)\r
101                     return prev;\r
102                 int fuel, bull;\r
103                 if (plane.Slot.Spec.Type == 47)\r
104                 {\r
105                     fuel = (int)Math.Ceiling(plane.Count * 1.5);\r
106                     bull = (int)(plane.Count * 0.7);\r
107                 }\r
108                 else\r
109                 {\r
110                     fuel = plane.Count;\r
111                     bull = (int)Math.Ceiling(plane.Count * 0.6);\r
112                 }\r
113                 return new[] {prev[0] + fuel, prev[1] + bull};\r
114             });\r
115         }\r
116 \r
117         public class PlaneInfo\r
118         {\r
119             public int State { get; set; }\r
120             public ItemStatus Slot { get; set; }\r
121             public int Count { get; set; }\r
122             public int MaxCount { get; set; }\r
123 \r
124             public string StateName\r
125             {\r
126                 get\r
127                 {\r
128                     switch (State)\r
129                     {\r
130                         case 0:\r
131                             return "未配備";\r
132                         case 1:\r
133                             return "配備中";\r
134                         case 2:\r
135                             return "配置転換中";\r
136                         default:\r
137                             return "";\r
138                     }\r
139                 }\r
140             }\r
141 \r
142             public AirBaseParams[] FighterPower => Slot.CalcFighterPowerInBase(Count);\r
143         }\r
144 \r
145         public void Inspect(dynamic json)\r
146         {\r
147             AllAirCorps = (from entry in (dynamic[])json\r
148                 group\r
149                     new AirCorpsInfo\r
150                     {\r
151                         Distance = CreateDistance(entry.api_distance),\r
152                         Action = (int)entry.api_action_kind,\r
153                         Planes = (from plane in (dynamic[])entry.api_plane_info\r
154                             select new PlaneInfo\r
155                             {\r
156                                 Slot = _itemInfo.GetStatus((int)plane.api_slotid),\r
157                                 State = (int)plane.api_state,\r
158                                 Count = plane.api_count() ? (int)plane.api_count : 0,\r
159                                 MaxCount = plane.api_max_count() ? (int)plane.api_max_count : 0\r
160                             }).ToArray()\r
161                     } by entry.api_area_id() ? (int)entry.api_area_id : 0\r
162                 into grp\r
163                 select new BaseInfo {AreaId = grp.Key, AirCorps = grp.ToArray()}).ToArray();\r
164         }\r
165 \r
166         public void InspectSetPlane(string request, dynamic json)\r
167         {\r
168             if (AllAirCorps == null)\r
169                 return;\r
170             var values = HttpUtility.ParseQueryString(request);\r
171             var airCorps = GetBaseInfo(values).AirCorps[int.Parse(values["api_base_id"]) - 1];\r
172             if (json.api_distance()) // 2016春イベにはない\r
173                 airCorps.Distance = CreateDistance(json.api_distance);\r
174             foreach (var planeInfo in json.api_plane_info)\r
175             {\r
176                 var planeId = (int)planeInfo.api_squadron_id - 1;\r
177                 var prev = airCorps.Planes[planeId];\r
178                 if (!prev.Slot.Empty)\r
179                     _relocatingPlanes.Add(prev.Slot.Id);\r
180                 airCorps.Planes[planeId] = new PlaneInfo\r
181                 {\r
182                     Slot = _itemInfo.GetStatus((int)planeInfo.api_slotid),\r
183                     State = (int)planeInfo.api_state,\r
184                     Count = planeInfo.api_count() ? (int)planeInfo.api_count : 0,\r
185                     MaxCount = planeInfo.api_max_count() ? (int)planeInfo.api_max_count : 0\r
186                 };\r
187             }\r
188         }\r
189 \r
190         private Distance CreateDistance(dynamic distance) => distance is double\r
191             // ReSharper disable once PossibleInvalidCastException\r
192             ? new Distance {Base = (int)distance}\r
193             : new Distance {Base = (int)distance.api_base, Bonus = (int)distance.api_bonus};\r
194 \r
195         public void InspectSupply(string request, dynamic json)\r
196         {\r
197             InspectSetPlane(request, json);\r
198         }\r
199 \r
200         public void InspectSetAction(string request)\r
201         {\r
202             if (AllAirCorps == null)\r
203                 return;\r
204             var values = HttpUtility.ParseQueryString(request);\r
205             var airCorps = GetBaseInfo(values).AirCorps;\r
206             foreach (var entry in\r
207                 values["api_base_id"].Split(',')\r
208                     .Zip(values["api_action_kind"].Split(','), (b, a) => new {baseId = b, action = a}))\r
209             {\r
210                 airCorps[int.Parse(entry.baseId) - 1].Action = int.Parse(entry.action);\r
211             }\r
212         }\r
213 \r
214         public void InspectExpandBase(string request, dynamic json)\r
215         {\r
216             var values = HttpUtility.ParseQueryString(request);\r
217             var baseInfo = GetBaseInfo(values);\r
218             var airCorps = baseInfo.AirCorps;\r
219             Array.Resize(ref airCorps, airCorps.Length + 1);\r
220             baseInfo.AirCorps = airCorps;\r
221             airCorps[airCorps.Length - 1] = new AirCorpsInfo\r
222             {\r
223                 Planes = ((dynamic[])json[0].api_plane_info).Select(plane =>\r
224                     new PlaneInfo {Slot = new ItemStatus()}).ToArray()\r
225             };\r
226         }\r
227 \r
228         private BaseInfo GetBaseInfo(NameValueCollection values)\r
229         {\r
230             var areaId = int.Parse(values["api_area_id"] ?? "0"); // 古いAPIに対応するため\r
231             return AllAirCorps.First(b => b.AreaId == areaId);\r
232         }\r
233 \r
234         public void InspectPlaneInfo(dynamic json)\r
235         {\r
236             _relocatingPlanes = json.api_base_convert_slot()\r
237                 ? new List<int>((int[])json.api_base_convert_slot)\r
238                 : new List<int>();\r
239         }\r
240 \r
241         public void InspectEventObject(dynamic json)\r
242         {\r
243             InspectPlaneInfo(json);\r
244         }\r
245 \r
246         public void SetItemHolder()\r
247         {\r
248             if (AllAirCorps == null)\r
249                 return;\r
250             var name = new[] {"第一", "第二", "第三"};\r
251             foreach (var baseInfo in AllAirCorps.Select((data, i) => new {data, i}))\r
252             {\r
253                 var areaName = baseInfo.data.AreaName;\r
254                 foreach (var airCorps in baseInfo.data.AirCorps.Select((data, i) => new {data, i}))\r
255                 {\r
256                     var ship = new ShipStatus\r
257                     {\r
258                         Id = 10000 + baseInfo.i * 1000 + airCorps.i,\r
259                         Spec = new ShipSpec {Name = areaName + " " + name[airCorps.i] + "航空隊"}\r
260                     };\r
261                     foreach (var plane in airCorps.data.Planes)\r
262                     {\r
263                         if (plane.State != 1)\r
264                             continue;\r
265                         _itemInfo.GetStatus(plane.Slot.Id).Holder = ship;\r
266                     }\r
267                 }\r
268             }\r
269             if (_relocatingPlanes == null)\r
270                 return;\r
271             var relocating = new ShipStatus {Id = 1500, Spec = new ShipSpec {Name = "配置転換中"}};\r
272             foreach (var id in _relocatingPlanes)\r
273                 _itemInfo.GetStatus(id).Holder = relocating;\r
274         }\r
275     }\r
276 }