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 // 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.Drawing;\r
21 using System.Linq;\r
22 using System.Web;\r
23 \r
24 namespace KancolleSniffer\r
25 {\r
26     public class ItemSpec\r
27     {\r
28         public int Id;\r
29         public string Name;\r
30         public int Type;\r
31         public string TypeName;\r
32         public int IconType;\r
33         public int AntiAir;\r
34         public int LoS;\r
35         public int AntiSubmarine;\r
36         public int Torpedo;\r
37         public int Bomber;\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                         return true;\r
56                 }\r
57                 return false;\r
58             }\r
59         }\r
60 \r
61         // http://ch.nicovideo.jp/biikame/blomaga/ar663428\r
62         public double LoSScaleFactor()\r
63         {\r
64             switch (Type)\r
65             {\r
66                 case 7: // 艦爆\r
67                     return 1.0376255;\r
68                 case 8: // 艦攻\r
69                     return 1.3677954;\r
70                 case 9: // 艦偵\r
71                     return 1.6592780;\r
72                 case 10: // 水偵\r
73                     return 2.0000000;\r
74                 case 11: // 水爆\r
75                     return 1.7787282;\r
76                 case 12: // 小型電探\r
77                     return 1.0045358;\r
78                 case 13: // 大型電探\r
79                     return 0.9906638;\r
80             }\r
81             if (Name == "探照灯")\r
82                 return 0.9067950;\r
83             return 0;\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                         return true;\r
101                 }\r
102                 return false;\r
103             }\r
104         }\r
105 \r
106         public bool IsSonar => Type == 14 || // ソナー\r
107                                Type == 40; // 大型ソナー\r
108 \r
109         public bool IsDepthCharge => Type == 15;\r
110 \r
111         public bool IsReconSeaplane => Type == 10;\r
112 \r
113         public Color Color\r
114         {\r
115             get\r
116             {\r
117                 switch (IconType)\r
118                 {\r
119                     case 1:\r
120                     case 2:\r
121                     case 3: // 主砲\r
122                     case 13: // 徹甲弾\r
123                         return Color.FromArgb(209, 89, 89);\r
124                     case 4: // 副砲\r
125                         return Color.FromArgb(253, 233, 0);\r
126                     case 5: // 魚雷\r
127                         return Color.FromArgb(88, 134, 170);\r
128                     case 6: // 艦戦\r
129                         return Color.FromArgb(93, 179, 108);\r
130                     case 7: // 艦爆\r
131                         return Color.FromArgb(223, 102, 102);\r
132                     case 8: // 艦攻\r
133                         return Color.FromArgb(95, 173, 234);\r
134                     case 9: // 艦偵\r
135                         return Color.FromArgb(254, 191, 0);\r
136                     case 10: // 水上機\r
137                         return Color.FromArgb(142, 203, 152);\r
138                     case 11: // 電探\r
139                         return Color.FromArgb(231, 153, 53);\r
140                     case 12: // 三式弾\r
141                         return Color.FromArgb(69, 175, 88);\r
142                     case 14: // 応急修理要員\r
143                         return Color.FromArgb(254, 254, 254);\r
144                     case 15: // 機銃\r
145                     case 16: // 高角砲\r
146                         return Color.FromArgb(102, 204, 118);\r
147                     case 17: // 爆雷\r
148                     case 18: // ソナー\r
149                         return Color.FromArgb(126, 203, 215);\r
150                     case 19: // 缶\r
151                         return Color.FromArgb(254, 195, 77);\r
152                     case 20: // 大発\r
153                         return Color.FromArgb(154, 163, 90);\r
154                     case 21: // オートジャイロ\r
155                         return Color.FromArgb(99, 203, 115);\r
156                     case 22: // 対潜哨戒機\r
157                         return Color.FromArgb(125, 205, 217);\r
158                     case 23: // 追加装甲\r
159                         return Color.FromArgb(152, 124, 172);\r
160                     case 24: // 探照灯\r
161                     case 27: // 照明弾\r
162                         return Color.FromArgb(254, 155, 0);\r
163                     case 25: // ドラム缶\r
164                         return Color.FromArgb(161, 161, 160);\r
165                     case 26: // 艦艇修理施設\r
166                         return Color.FromArgb(175, 156, 126);\r
167                     case 28: // 司令部施設\r
168                         return Color.FromArgb(204, 172, 252);\r
169                     case 29: // 航空要員\r
170                         return Color.FromArgb(206, 166, 108);\r
171                     case 30: // 高射装置\r
172                         return Color.FromArgb(137, 153, 77);\r
173                     case 31: // 対地装備\r
174                         return Color.FromArgb(253, 49, 49);\r
175                     case 32: // 水上艦要員\r
176                         return Color.FromArgb(188, 238, 155);\r
177                     case 33: // 大型飛行艇\r
178                         return Color.FromArgb(142, 203, 152);\r
179                     case 34: // 戦闘糧食\r
180                         return Color.FromArgb(254, 254, 254);\r
181                     default:\r
182                         return SystemColors.Control;\r
183                 }\r
184             }\r
185         }\r
186     }\r
187 \r
188     public class ItemStatus\r
189     {\r
190         public ItemSpec Spec { get; set; }\r
191         public int Level { get; set; }\r
192         public int Alv { get; set; }\r
193         public ShipStatus Ship { get; set; }\r
194 \r
195         public ItemStatus()\r
196         {\r
197             Spec = new ItemSpec();\r
198             Ship = new ShipStatus();\r
199         }\r
200     }\r
201 \r
202     public class ItemInfo : IHaveState\r
203     {\r
204         private int _nowShips, _nowEquips;\r
205         private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();\r
206         private readonly Dictionary<int, ItemStatus> _itemInfo = new Dictionary<int, ItemStatus>();\r
207 \r
208         public int MaxShips { get; private set; }\r
209         public int MarginShips { get; set; }\r
210         public bool RingShips { get; set; }\r
211         public int MaxEquips { get; private set; }\r
212         public int MarginEquips { get; set; }\r
213         public bool RingEquips { get; set; }\r
214         public MaterialCount[] MaterialHistory { get; }\r
215 \r
216         public bool NeedSave\r
217         {\r
218             get { return MaterialHistory.Any(m => m.NeedSave); }\r
219             private set\r
220             {\r
221                 foreach (var m in MaterialHistory)\r
222                     m.NeedSave = value;\r
223             }\r
224         }\r
225 \r
226         public int NowShips\r
227         {\r
228             get { return _nowShips; }\r
229             set\r
230             {\r
231                 if (MaxShips != 0)\r
232                 {\r
233                     var limit = MaxShips - MarginShips;\r
234                     RingShips = _nowShips < limit && value >= limit;\r
235                 }\r
236                 _nowShips = value;\r
237             }\r
238         }\r
239 \r
240         public bool TooManyShips => MaxShips != 0 && NowShips >= MaxShips - MarginShips;\r
241 \r
242         public int NowEquips\r
243         {\r
244             get { return _nowEquips; }\r
245             private set\r
246             {\r
247                 if (MaxEquips != 0)\r
248                 {\r
249                     var limit = MaxEquips - MarginEquips;\r
250                     RingEquips = _nowEquips < limit && value >= limit;\r
251                 }\r
252                 _nowEquips = value;\r
253             }\r
254         }\r
255 \r
256         public bool TooManyEquips => MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips;\r
257 \r
258         public ItemInfo()\r
259         {\r
260             MaterialHistory = new MaterialCount[Enum.GetValues(typeof(Material)).Length];\r
261             foreach (Material m in Enum.GetValues(typeof(Material)))\r
262                 MaterialHistory[(int)m] = new MaterialCount();\r
263             MarginShips = 4;\r
264             MarginEquips = 10;\r
265         }\r
266 \r
267         public void InspectBasic(dynamic json)\r
268         {\r
269             MaxShips = (int)json.api_max_chara;\r
270             MaxEquips = (int)json.api_max_slotitem;\r
271         }\r
272 \r
273         public void InspectMaterial(dynamic json)\r
274         {\r
275             foreach (var entry in json)\r
276                 MaterialHistory[(int)entry.api_id - 1].Now = (int)entry.api_value;\r
277         }\r
278 \r
279         public void InspectMaster(dynamic json)\r
280         {\r
281             var dict = new Dictionary<int, string>();\r
282             foreach (var entry in json.api_mst_slotitem_equiptype)\r
283                 dict[(int)entry.api_id] = entry.api_name;\r
284             foreach (var entry in json.api_mst_slotitem)\r
285             {\r
286                 _itemSpecs[(int)entry.api_id] = new ItemSpec\r
287                 {\r
288                     Id = (int)entry.api_id,\r
289                     Name = (string)entry.api_name,\r
290                     Type = (int)entry.api_type[2],\r
291                     TypeName = dict[(int)entry.api_type[2]],\r
292                     IconType = (int)entry.api_type[3],\r
293                     AntiAir = (int)entry.api_tyku,\r
294                     LoS = (int)entry.api_saku,\r
295                     AntiSubmarine = (int)entry.api_tais,\r
296                     Torpedo = (int)entry.api_raig,\r
297                     Bomber = (int)entry.api_baku\r
298                 };\r
299             }\r
300             _itemSpecs[-1] = new ItemSpec();\r
301         }\r
302 \r
303         public void InspectSlotItem(dynamic json, bool full = false)\r
304         {\r
305             if (!json.IsArray)\r
306                 json = new[] {json};\r
307             if (full)\r
308             {\r
309                 _itemInfo.Clear();\r
310                 _itemInfo[-1] = _itemInfo[0] = new ItemStatus();\r
311             }\r
312             foreach (var entry in json)\r
313             {\r
314                 _itemInfo[(int)entry.api_id] = new ItemStatus\r
315                 {\r
316                     Spec = _itemSpecs[(int)entry.api_slotitem_id],\r
317                     Level = entry.api_level() ? (int)entry.api_level : 0,\r
318                     Alv = entry.api_alv() ? (int)entry.api_alv : 0\r
319                 };\r
320             }\r
321             NowEquips = _itemInfo.Count - 1;\r
322         }\r
323 \r
324         public void InspectCreateItem(dynamic json)\r
325         {\r
326             var m = (dynamic[])json.api_material;\r
327             for (var i = 0; i < m.Length; i++)\r
328                 MaterialHistory[i].Now = (int)m[i];\r
329             if (!json.IsDefined("api_slot_item"))\r
330                 return;\r
331             InspectSlotItem(json.api_slot_item);\r
332         }\r
333 \r
334         public void InspectGetShip(dynamic json)\r
335         {\r
336             NowShips += 1;\r
337             if (json.api_slotitem == null) // まるゆにはスロットがない\r
338                 return;\r
339             InspectSlotItem(json.api_slotitem);\r
340         }\r
341 \r
342         public void InspectDestroyItem(string request, dynamic json)\r
343         {\r
344             var values = HttpUtility.ParseQueryString(request);\r
345             DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray());\r
346             var get = (int[])json.api_get_material;\r
347             for (var i = 0; i < get.Length; i++)\r
348                 MaterialHistory[i].Now += get[i];\r
349         }\r
350 \r
351         public void InspectRemodelSlot(dynamic json)\r
352         {\r
353             var after = (int[])json.api_after_material;\r
354             for (var i = 0; i < after.Length; i++)\r
355                 MaterialHistory[i].Now = after[i];\r
356             if (json.api_after_slot())\r
357                 InspectSlotItem(json.api_after_slot);\r
358             if (!json.api_use_slot_id())\r
359                 return;\r
360             DeleteItems(((int[])json.api_use_slot_id));\r
361         }\r
362 \r
363         public void DeleteItems(int[] ids)\r
364         {\r
365             foreach (var id in ids.Where(id => id != -1))\r
366             {\r
367                 _itemInfo.Remove(id);\r
368                 NowEquips--;\r
369             }\r
370         }\r
371 \r
372         public void CountNewItems(int[] ids)\r
373         {\r
374             foreach (var id in ids.Where(id => id != -1 && !_itemInfo.ContainsKey(id)))\r
375             {\r
376                 _itemInfo[id] = new ItemStatus();\r
377                 NowEquips++;\r
378             }\r
379         }\r
380 \r
381         public void InspectMissionResult(dynamic json)\r
382         {\r
383             if ((int)json.api_clear_result == 0) // 失敗\r
384                 return;\r
385             var get = (int[])json.api_get_material;\r
386             for (var i = 0; i < get.Length; i++)\r
387                 MaterialHistory[i].Now += get[i];\r
388         }\r
389 \r
390         public ItemSpec this[int id] => GetSpecById(id);\r
391 \r
392         public ItemSpec GetSpecById(int id) => _itemInfo[id].Spec;\r
393 \r
394         public ItemSpec GetSpecByItemId(int id) => _itemSpecs[id];\r
395 \r
396         public Dictionary<int, ItemStatus> ItemDict => _itemInfo;\r
397 \r
398         public void SetItemOwner(ShipStatus[] shipList)\r
399         {\r
400             foreach (var e in _itemInfo)\r
401                 e.Value.Ship = new ShipStatus();\r
402             foreach (var s in shipList)\r
403             {\r
404                 foreach (var id in s.Slot)\r
405                     _itemInfo[id].Ship = s;\r
406             }\r
407         }\r
408 \r
409         public void SaveState(Status status)\r
410         {\r
411             NeedSave = false;\r
412             status.MatreialHistory = MaterialHistory;\r
413         }\r
414 \r
415         public void LoadState(Status status)\r
416         {\r
417             status.MatreialHistory?.CopyTo(MaterialHistory, 0);\r
418         }\r
419     }\r
420 \r
421     public enum Material\r
422     {\r
423         Fuel,\r
424         Bullet,\r
425         Steal,\r
426         Bouxite,\r
427         Burner,\r
428         Bucket,\r
429         Development,\r
430         Screw,\r
431     }\r
432 \r
433     public class MaterialCount\r
434     {\r
435         private int _now;\r
436 \r
437         public int BegOfDay { get; set; }\r
438         public int BegOfWeek { get; set; }\r
439         public DateTime LastSet { get; set; }\r
440         public bool NeedSave { get; set; }\r
441 \r
442         public int Now\r
443         {\r
444             get { return _now; }\r
445             set\r
446             {\r
447                 var prev = _now;\r
448                 _now = value;\r
449                 if (Status.Restoring) // JSONから値を復旧するときは履歴に触らない\r
450                     return;\r
451                 if (_now != prev)\r
452                     NeedSave = true;\r
453                 if (LastSet == DateTime.MinValue)\r
454                 {\r
455                     BegOfDay = BegOfWeek = value;\r
456                     LastSet = DateTime.Now;\r
457                     return;\r
458                 }\r
459                 UpdateHistory(prev);\r
460                 LastSet = DateTime.Now;\r
461             }\r
462         }\r
463 \r
464         private void UpdateHistory(int prev)\r
465         {\r
466             var morning = DateTime.Today.AddHours(5);\r
467             var dow = (int)morning.DayOfWeek;\r
468             var monday = morning.AddDays(dow == 0 ? -6 : -dow + 1);\r
469             if (DateTime.Now >= morning && LastSet < morning)\r
470                 BegOfDay = prev;\r
471             if (DateTime.Now >= monday && LastSet < monday)\r
472                 BegOfWeek = prev;\r
473         }\r
474     }\r
475 }