OSDN Git Service

基地航空隊の防空時の偵察機補正込みの制空値を計算する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ItemInfo.cs
1 // Copyright (C) 2013, 2014, 2015 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.Collections.Generic;\r
16 using System.Drawing;\r
17 using System.Linq;\r
18 using static System.Math;\r
19 \r
20 namespace KancolleSniffer\r
21 {\r
22     public class ItemSpec\r
23     {\r
24         public static bool IncreaceLandPowerTp = true;\r
25         public int Id;\r
26         public string Name;\r
27         public int Type;\r
28         public string TypeName;\r
29         public int IconType;\r
30         public int AntiAir;\r
31         public int LoS;\r
32         public int AntiSubmarine;\r
33         public int Torpedo;\r
34         public int Bomber;\r
35         public int Interception;\r
36         public int AntiBomber;\r
37 \r
38         public ItemSpec()\r
39         {\r
40             Id = -1;\r
41             Name = "";\r
42         }\r
43 \r
44         public bool CanAirCombat\r
45         {\r
46             get\r
47             {\r
48                 switch (Type)\r
49                 {\r
50                     case 6: // 艦戦\r
51                     case 7: // 艦爆\r
52                     case 8: // 艦攻\r
53                     case 11: // 水爆\r
54                     case 45: // 水戦\r
55                         return true;\r
56                 }\r
57                 return false;\r
58             }\r
59         }\r
60 \r
61         // http://ja.kancolle.wikia.com/wiki/%E3%83%9E%E3%83%83%E3%83%97%E7%B4%A2%E6%95%B5\r
62         public double LoSScaleFactor\r
63         {\r
64             get\r
65             {\r
66                 switch (Type)\r
67                 {\r
68                     case 8: // 艦攻\r
69                         return 0.8;\r
70                     case 9: // 艦偵\r
71                         return 1;\r
72                     case 10: // 水偵\r
73                         return 1.2;\r
74                     case 11: // 水爆\r
75                         return 1.1;\r
76                     default:\r
77                         return 0.6;\r
78                 }\r
79             }\r
80         }\r
81 \r
82         public bool IsAircraft\r
83         {\r
84             get\r
85             {\r
86                 switch (Type)\r
87                 {\r
88                     case 6:\r
89                     case 7:\r
90                     case 8:\r
91                     case 9:\r
92                     case 10:\r
93                     case 11:\r
94                     case 25: // オートジャイロ\r
95                     case 26: // 対潜哨戒機\r
96                     case 41: // 大艇\r
97                     case 45:\r
98                     case 47: // 陸上攻撃機\r
99                     case 48: // 局地戦闘機\r
100                         return true;\r
101                 }\r
102                 return false;\r
103             }\r
104         }\r
105 \r
106         public int RealAntiSubmarine\r
107         {\r
108             get\r
109             {\r
110                 switch (Type)\r
111                 {\r
112                     case 1: // 小口径(12.7cm連装高角砲(後期型))\r
113                     case 10: // 水偵\r
114                     case 12: // 小型電探(22号対水上電探改四)\r
115                     case 45: // 水戦\r
116                         return 0;\r
117                     default:\r
118                         return AntiSubmarine;\r
119                 }\r
120             }\r
121         }\r
122 \r
123         public bool IsSonar => Type == 14 || // ソナー\r
124                                Type == 40; // 大型ソナー\r
125 \r
126         public bool IsDepthCharge => Type == 15;\r
127 \r
128         public bool IsRepairFacility => Type == 31;\r
129 \r
130         public double ContactTriggerRate\r
131         {\r
132             get\r
133             {\r
134                 switch (Type)\r
135                 {\r
136                     case 9: // 艦偵\r
137                     case 10: // 水偵\r
138                     case 41: // 大艇\r
139                         return 0.04;\r
140                     default:\r
141                         return 0;\r
142                 }\r
143             }\r
144         }\r
145 \r
146         public double TransportPoint\r
147         {\r
148             get\r
149             {\r
150                 switch (Id)\r
151                 {\r
152                     case 75: // ドラム缶(輸送用)\r
153                         return 5.0;\r
154                     case 68: // 大発動艇\r
155                         return 8.0;\r
156                     case 166: // 大発動艇(八九式中戦車&陸戦隊)\r
157                         return IncreaceLandPowerTp ? 13.0 : 8.0;\r
158                     case 167: // 特二式内火艇\r
159                         return IncreaceLandPowerTp ? 7.0 : 2.0;\r
160                     case 145: // 戦闘糧食\r
161                         return 1.0;\r
162                     case 150: // 秋刀魚の缶詰\r
163                         return 1.0;\r
164                     default:\r
165                         return 0;\r
166                 }\r
167             }\r
168         }\r
169 \r
170         public double AirDefenceBonus\r
171         {\r
172             get\r
173             {\r
174                 switch (Type)\r
175                 {\r
176                     case 9:\r
177                         return LoS <= 7 ? 1.2 : 1.3;\r
178                     case 10:\r
179                     case 41:\r
180                         return LoS <= 7 ? 1.1 : LoS <= 8 ? 1.13 : 1.16;\r
181                 }\r
182                 return 1;\r
183             }\r
184         }\r
185 \r
186         public Color Color\r
187         {\r
188             get\r
189             {\r
190                 switch (IconType)\r
191                 {\r
192                     case 1:\r
193                     case 2:\r
194                     case 3: // 主砲\r
195                     case 13: // 徹甲弾\r
196                         return Color.FromArgb(209, 89, 89);\r
197                     case 4: // 副砲\r
198                         return Color.FromArgb(253, 233, 0);\r
199                     case 5: // 魚雷\r
200                         return Color.FromArgb(88, 134, 170);\r
201                     case 6: // 艦戦\r
202                         return Color.FromArgb(93, 179, 108);\r
203                     case 7: // 艦爆\r
204                         return Color.FromArgb(223, 102, 102);\r
205                     case 8: // 艦攻\r
206                         return Color.FromArgb(95, 173, 234);\r
207                     case 9: // 艦偵\r
208                         return Color.FromArgb(254, 191, 0);\r
209                     case 10: // 水上機\r
210                         return Color.FromArgb(142, 203, 152);\r
211                     case 11: // 電探\r
212                         return Color.FromArgb(231, 153, 53);\r
213                     case 12: // 三式弾\r
214                         return Color.FromArgb(69, 175, 88);\r
215                     case 14: // 応急修理要員\r
216                         return Color.FromArgb(254, 254, 254);\r
217                     case 15: // 機銃\r
218                     case 16: // 高角砲\r
219                         return Color.FromArgb(102, 204, 118);\r
220                     case 17: // 爆雷\r
221                     case 18: // ソナー\r
222                         return Color.FromArgb(126, 203, 215);\r
223                     case 19: // 缶\r
224                         return Color.FromArgb(254, 195, 77);\r
225                     case 20: // 大発\r
226                     case 36: // 特型内火艇\r
227                         return Color.FromArgb(154, 163, 90);\r
228                     case 21: // オートジャイロ\r
229                         return Color.FromArgb(99, 203, 115);\r
230                     case 22: // 対潜哨戒機\r
231                         return Color.FromArgb(125, 205, 217);\r
232                     case 23: // 追加装甲\r
233                         return Color.FromArgb(152, 124, 172);\r
234                     case 24: // 探照灯\r
235                     case 27: // 照明弾\r
236                         return Color.FromArgb(254, 155, 0);\r
237                     case 25: // ドラム缶\r
238                         return Color.FromArgb(161, 161, 160);\r
239                     case 26: // 艦艇修理施設\r
240                         return Color.FromArgb(175, 156, 126);\r
241                     case 28: // 司令部施設\r
242                         return Color.FromArgb(204, 172, 252);\r
243                     case 29: // 航空要員\r
244                         return Color.FromArgb(206, 166, 108);\r
245                     case 30: // 高射装置\r
246                         return Color.FromArgb(137, 153, 77);\r
247                     case 31: // 対地装備\r
248                         return Color.FromArgb(253, 49, 49);\r
249                     case 32: // 水上艦要員\r
250                         return Color.FromArgb(188, 238, 155);\r
251                     case 33: // 大型飛行艇\r
252                         return Color.FromArgb(142, 203, 152);\r
253                     case 34: // 戦闘糧食\r
254                         return Color.FromArgb(254, 254, 254);\r
255                     case 35: // 補給物資\r
256                         return Color.FromArgb(90, 200, 155);\r
257                     case 37: // 陸上攻撃機\r
258                         return Color.FromArgb(57, 182, 78);\r
259                     case 38: // 局地戦闘機\r
260                         return Color.FromArgb(57, 182, 78);\r
261                     default:\r
262                         return SystemColors.Control;\r
263                 }\r
264             }\r
265         }\r
266     }\r
267 \r
268     public class ItemStatus\r
269     {\r
270         public int Id { get; set; }\r
271         public ItemSpec Spec { get; set; } = new ItemSpec();\r
272         public int Level { get; set; }\r
273         public int Alv { get; set; }\r
274         public ShipStatus Holder { get; set; }\r
275 \r
276         public ItemStatus()\r
277         {\r
278             Id = -1;\r
279         }\r
280 \r
281         public ItemStatus(int id)\r
282         {\r
283             Id = id == 0 ? -1 : id;\r
284         }\r
285 \r
286         private readonly double[] _alvBonusMin =\r
287         {\r
288             Sqrt(0.0), Sqrt(1.0), Sqrt(2.5), Sqrt(4.0), Sqrt(5.5), Sqrt(7.0),\r
289             Sqrt(8.5), Sqrt(10.0)\r
290         };\r
291 \r
292         private readonly double[] _alvBonusMax =\r
293         {\r
294             Sqrt(0.9), Sqrt(2.4), Sqrt(3.9), Sqrt(5.4), Sqrt(6.9), Sqrt(8.4),\r
295             Sqrt(9.9), Sqrt(12.0)\r
296         };\r
297 \r
298         private readonly Dictionary<int, int[]> _alvTypeBonus = new Dictionary<int, int[]>\r
299         {\r
300             {06, new[] {0, 0, 2, 5, 9, 14, 14, 22}}, // 艦戦\r
301             {07, new[] {0, 0, 0, 0, 0, 0, 0, 0}}, // 艦爆\r
302             {08, new[] {0, 0, 0, 0, 0, 0, 0, 0}}, // 艦攻\r
303             {11, new[] {0, 0, 1, 1, 1, 3, 3, 6}}, // 水爆\r
304             {45, new[] {0, 0, 2, 5, 9, 14, 14, 22}}, // 水戦\r
305             {48, new[] {0, 0, 2, 5, 9, 14, 14, 22}} // 局地戦闘機\r
306         };\r
307 \r
308         public double[] AlvBonus\r
309         {\r
310             get\r
311             {\r
312                 int[] table;\r
313                 if (!_alvTypeBonus.TryGetValue(Spec.Type, out table))\r
314                     return new[] {0.0, 0.0};\r
315                 return new[] {table[Alv] + _alvBonusMin[Alv], table[Alv] + _alvBonusMax[Alv]};\r
316             }\r
317         }\r
318 \r
319         public double FighterPowerLevelBonus\r
320         {\r
321             get\r
322             {\r
323                 if (Spec.Type == 6)\r
324                     return 0.2 * Level;\r
325                 if (Spec.Type == 7) // 改修可能なのは爆戦のみ\r
326                     return 0.25 * Level;\r
327                 return 0;\r
328             }\r
329         }\r
330 \r
331         public double LoSLevelBonus\r
332         {\r
333             get\r
334             {\r
335                 switch (Spec.Type)\r
336                 {\r
337                     case 10: // 水偵\r
338                         return 1.2 * Sqrt(Level);\r
339                     case 12: // 小型電探\r
340                     case 13: // 大型電探\r
341                         return 1.25 * Sqrt(Level);\r
342                     default:\r
343                         return 0;\r
344                 }\r
345             }\r
346         }\r
347 \r
348         public double FirePowerLevelBonus\r
349         {\r
350             get\r
351             {\r
352                 switch (Spec.Type)\r
353                 {\r
354                     case 1: // 小口径\r
355                     case 2: // 中口径\r
356                         return Sqrt(Level);\r
357                     case 3: // 大口径\r
358                         return 1.5 * Sqrt(Level);\r
359                     case 4: // 副砲\r
360                         return Sqrt(Level);\r
361                     case 14: // ソナー\r
362                     case 15: // 爆雷\r
363                         return 0.75 * Sqrt(Level);\r
364                     case 19: // 徹甲弾\r
365                         return Sqrt(Level);\r
366                     default:\r
367                         return 0;\r
368                 }\r
369             }\r
370         }\r
371 \r
372         public double TorpedoLevelBonus\r
373         {\r
374             get\r
375             {\r
376                 if (Spec.Type == 5) // 魚雷\r
377                     return 1.2 * Sqrt(Level);\r
378                 if (Spec.Type == 21) // 機銃\r
379                     return 1.2 * Sqrt(Level);\r
380                 return 0;\r
381             }\r
382         }\r
383 \r
384         public double AntiSubmarineLevelBonus\r
385         {\r
386             get\r
387             {\r
388                 switch (Spec.Type)\r
389                 {\r
390                     case 14:\r
391                     case 15:\r
392                         return Sqrt(Level);\r
393                     default:\r
394                         return 0;\r
395                 }\r
396             }\r
397         }\r
398 \r
399         public double NightBattleLevelBonus\r
400         {\r
401             get\r
402             {\r
403                 switch (Spec.Type)\r
404                 {\r
405                     case 1: // 小口径\r
406                     case 2: // 中口径\r
407                     case 3: // 大口径\r
408                         return Sqrt(Level);\r
409                     case 4: // 副砲\r
410                         return Sqrt(Level);\r
411                     case 5: // 魚雷\r
412                     case 19: // 徹甲弾\r
413                     case 29: // 探照灯\r
414                     case 36: // 高射装置\r
415                     case 42: // 大型探照灯\r
416                         return Sqrt(Level);\r
417                     default:\r
418                         return 0;\r
419                 }\r
420             }\r
421         }\r
422     }\r
423 \r
424     public class ItemInfo\r
425     {\r
426         private int _nowShips, _nowEquips;\r
427         private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();\r
428         private readonly Dictionary<int, ItemStatus> _itemInfo = new Dictionary<int, ItemStatus>();\r
429         private readonly Dictionary<int, string> _useItemName = new Dictionary<int, string>();\r
430 \r
431         public int MaxShips { get; private set; }\r
432         public int MarginShips { get; set; }\r
433         public bool RingShips { get; set; }\r
434         public int MaxEquips { get; private set; }\r
435         public int MarginEquips { get; set; }\r
436         public bool RingEquips { get; set; }\r
437 \r
438         public int NowShips\r
439         {\r
440             get { return _nowShips; }\r
441             set\r
442             {\r
443                 if (MaxShips != 0)\r
444                 {\r
445                     var limit = MaxShips - MarginShips;\r
446                     RingShips = RingShips || _nowShips < limit && value >= limit;\r
447                 }\r
448                 _nowShips = value;\r
449             }\r
450         }\r
451 \r
452         public bool TooManyShips => MaxShips != 0 && NowShips >= MaxShips - MarginShips;\r
453 \r
454         public int NowEquips\r
455         {\r
456             get { return _nowEquips; }\r
457             private set\r
458             {\r
459                 if (MaxEquips != 0)\r
460                 {\r
461                     var limit = MaxEquips - MarginEquips;\r
462                     RingEquips = RingEquips || _nowEquips < limit && value >= limit;\r
463                 }\r
464                 _nowEquips = value;\r
465             }\r
466         }\r
467 \r
468         public bool TooManyEquips => MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips;\r
469 \r
470         public ItemInfo()\r
471         {\r
472             MarginShips = 4;\r
473             MarginEquips = 10;\r
474         }\r
475 \r
476         public void InspectBasic(dynamic json)\r
477         {\r
478             MaxShips = (int)json.api_max_chara;\r
479             var check = MaxEquips == 0;\r
480             MaxEquips = (int)json.api_max_slotitem;\r
481             if (check)\r
482                 RingEquips = NowEquips >= MaxEquips - MarginEquips;\r
483         }\r
484 \r
485         public void InspectMaster(dynamic json)\r
486         {\r
487             var dict = new Dictionary<int, string>();\r
488             foreach (var entry in json.api_mst_slotitem_equiptype)\r
489                 dict[(int)entry.api_id] = entry.api_name;\r
490             foreach (var entry in json.api_mst_slotitem)\r
491             {\r
492                 var type = (int)entry.api_type[2];\r
493                 _itemSpecs[(int)entry.api_id] = new ItemSpec\r
494                 {\r
495                     Id = (int)entry.api_id,\r
496                     Name = (string)entry.api_name,\r
497                     Type = type,\r
498                     TypeName = dict[(int)entry.api_type[2]],\r
499                     IconType = (int)entry.api_type[3],\r
500                     AntiAir = (int)entry.api_tyku,\r
501                     LoS = (int)entry.api_saku,\r
502                     AntiSubmarine = (int)entry.api_tais,\r
503                     Torpedo = (int)entry.api_raig,\r
504                     Bomber = (int)entry.api_baku,\r
505                     Interception = type == 48 ? (int)entry.api_houk : 0, // 局地戦闘機は回避の値が迎撃\r
506                     AntiBomber = type == 48 ? (int)entry.api_houm : 0 // 〃命中の値が対爆\r
507                 };\r
508             }\r
509             _itemSpecs[-1] = _itemSpecs[0] = new ItemSpec();\r
510             foreach (var entry in json.api_mst_useitem)\r
511                 _useItemName[(int)entry.api_id] = entry.api_name;\r
512         }\r
513 \r
514         public void InspectSlotItem(dynamic json, bool full = false)\r
515         {\r
516             if (!json.IsArray)\r
517                 json = new[] {json};\r
518             if (full)\r
519             {\r
520                 _itemInfo.Clear();\r
521                 _itemInfo[-1] = new ItemStatus();\r
522             }\r
523             foreach (var entry in json)\r
524             {\r
525                 var id = (int)entry.api_id;\r
526                 _itemInfo[id] = new ItemStatus(id)\r
527                 {\r
528                     Spec = _itemSpecs[(int)entry.api_slotitem_id],\r
529                     Level = entry.api_level() ? (int)entry.api_level : 0,\r
530                     Alv = entry.api_alv() ? (int)entry.api_alv : 0\r
531                 };\r
532             }\r
533             NowEquips = _itemInfo.Count - 1;\r
534         }\r
535 \r
536         public void InspectCreateItem(dynamic json)\r
537         {\r
538             if (!json.IsDefined("api_slot_item"))\r
539                 return;\r
540             InspectSlotItem(json.api_slot_item);\r
541         }\r
542 \r
543         public void InspectGetShip(dynamic json)\r
544         {\r
545             NowShips += 1;\r
546             if (json.api_slotitem == null) // まるゆにはスロットがない\r
547                 return;\r
548             InspectSlotItem(json.api_slotitem);\r
549         }\r
550 \r
551         public void InspectDestroyItem(string request, dynamic json)\r
552         {\r
553             var values = HttpUtility.ParseQueryString(request);\r
554             DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray());\r
555         }\r
556 \r
557         public void InspectRemodelSlot(dynamic json)\r
558         {\r
559             if (json.api_after_slot())\r
560                 InspectSlotItem(json.api_after_slot);\r
561             if (!json.api_use_slot_id())\r
562                 return;\r
563             DeleteItems((int[])json.api_use_slot_id);\r
564         }\r
565 \r
566         public void DeleteItems(ItemStatus[] items)\r
567         {\r
568             DeleteItems(items.Select(item => item.Id));\r
569         }\r
570 \r
571         private void DeleteItems(IEnumerable<int> ids)\r
572         {\r
573             foreach (var id in ids.Where(id => id != -1))\r
574             {\r
575                 _itemInfo.Remove(id);\r
576                 NowEquips--;\r
577             }\r
578         }\r
579 \r
580         public ItemSpec GetSpecByItemId(int id) => _itemSpecs[id];\r
581 \r
582         public string GetName(int id) => GetStatus(id).Spec.Name;\r
583 \r
584         public ItemStatus GetStatus(int id)\r
585         {\r
586             ItemStatus item;\r
587             return _itemInfo.TryGetValue(id, out item) ? item : new ItemStatus(id);\r
588         }\r
589 \r
590         public void ClearHolder()\r
591         {\r
592             foreach (var item in _itemInfo.Values)\r
593                 item.Holder = new ShipStatus();\r
594         }\r
595 \r
596         public ItemStatus[] ItemList => (from e in _itemInfo where e.Key != -1 select e.Value).ToArray();\r
597 \r
598         public string GetUseItemName(int id) => _useItemName[id];\r
599     }\r
600 }