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