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                     default:\r
178                         return SystemColors.Control;\r
179                 }\r
180             }\r
181         }\r
182     }\r
183 \r
184     public class ItemStatus\r
185     {\r
186         public ItemSpec Spec { get; set; }\r
187         public int Level { get; set; }\r
188         public int Alv { get; set; }\r
189         public ShipStatus Ship { get; set; }\r
190 \r
191         public ItemStatus()\r
192         {\r
193             Spec = new ItemSpec();\r
194             Ship = new ShipStatus();\r
195         }\r
196     }\r
197 \r
198     public class ItemInfo : IHaveState\r
199     {\r
200         private int _nowShips, _nowEquips;\r
201         private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();\r
202         private readonly Dictionary<int, ItemStatus> _itemInfo = new Dictionary<int, ItemStatus>();\r
203 \r
204         public int MaxShips { get; private set; }\r
205         public int MarginShips { get; set; }\r
206         public bool RingShips { get; set; }\r
207         public int MaxEquips { get; private set; }\r
208         public int MarginEquips { get; set; }\r
209         public bool RingEquips { get; set; }\r
210         public MaterialCount[] MaterialHistory { get; }\r
211 \r
212         public bool NeedSave\r
213         {\r
214             get { return MaterialHistory.Any(m => m.NeedSave); }\r
215             private set\r
216             {\r
217                 foreach (var m in MaterialHistory)\r
218                     m.NeedSave = value;\r
219             }\r
220         }\r
221 \r
222         public int NowShips\r
223         {\r
224             get { return _nowShips; }\r
225             set\r
226             {\r
227                 if (MaxShips != 0)\r
228                 {\r
229                     var limit = MaxShips - MarginShips;\r
230                     RingShips = _nowShips < limit && value >= limit;\r
231                 }\r
232                 _nowShips = value;\r
233             }\r
234         }\r
235 \r
236         public bool TooManyShips => MaxShips != 0 && NowShips >= MaxShips - MarginShips;\r
237 \r
238         public int NowEquips\r
239         {\r
240             get { return _nowEquips; }\r
241             private set\r
242             {\r
243                 if (MaxEquips != 0)\r
244                 {\r
245                     var limit = MaxEquips - MarginEquips;\r
246                     RingEquips = _nowEquips < limit && value >= limit;\r
247                 }\r
248                 _nowEquips = value;\r
249             }\r
250         }\r
251 \r
252         public bool TooManyEquips => MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips;\r
253 \r
254         public ItemInfo()\r
255         {\r
256             MaterialHistory = new MaterialCount[Enum.GetValues(typeof(Material)).Length];\r
257             foreach (Material m in Enum.GetValues(typeof(Material)))\r
258                 MaterialHistory[(int)m] = new MaterialCount();\r
259             MarginShips = 4;\r
260             MarginEquips = 10;\r
261         }\r
262 \r
263         public void InspectBasic(dynamic json)\r
264         {\r
265             MaxShips = (int)json.api_max_chara;\r
266             MaxEquips = (int)json.api_max_slotitem;\r
267         }\r
268 \r
269         public void InspectMaterial(dynamic json)\r
270         {\r
271             foreach (var entry in json)\r
272                 MaterialHistory[(int)entry.api_id - 1].Now = (int)entry.api_value;\r
273         }\r
274 \r
275         public void InspectMaster(dynamic json)\r
276         {\r
277             var dict = new Dictionary<int, string>();\r
278             foreach (var entry in json.api_mst_slotitem_equiptype)\r
279                 dict[(int)entry.api_id] = entry.api_name;\r
280             foreach (var entry in json.api_mst_slotitem)\r
281             {\r
282                 _itemSpecs[(int)entry.api_id] = new ItemSpec\r
283                 {\r
284                     Id = (int)entry.api_id,\r
285                     Name = (string)entry.api_name,\r
286                     Type = (int)entry.api_type[2],\r
287                     TypeName = dict[(int)entry.api_type[2]],\r
288                     IconType = (int)entry.api_type[3],\r
289                     AntiAir = (int)entry.api_tyku,\r
290                     LoS = (int)entry.api_saku,\r
291                     AntiSubmarine = (int)entry.api_tais,\r
292                     Torpedo = (int)entry.api_raig,\r
293                     Bomber = (int)entry.api_baku\r
294                 };\r
295             }\r
296             _itemSpecs[-1] = new ItemSpec();\r
297         }\r
298 \r
299         public void InspectSlotItem(dynamic json, bool full = false)\r
300         {\r
301             if (!json.IsArray)\r
302                 json = new[] {json};\r
303             if (full)\r
304             {\r
305                 _itemInfo.Clear();\r
306                 _itemInfo[-1] = new ItemStatus();\r
307             }\r
308             foreach (var entry in json)\r
309             {\r
310                 _itemInfo[(int)entry.api_id] = new ItemStatus\r
311                 {\r
312                     Spec = _itemSpecs[(int)entry.api_slotitem_id],\r
313                     Level = entry.api_level() ? (int)entry.api_level : 0,\r
314                     Alv = entry.api_alv() ? (int)entry.api_alv : 0\r
315                 };\r
316             }\r
317             NowEquips = _itemInfo.Count - 1;\r
318         }\r
319 \r
320         public void InspectCreateItem(dynamic json)\r
321         {\r
322             var m = (dynamic[])json.api_material;\r
323             for (var i = 0; i < m.Length; i++)\r
324                 MaterialHistory[i].Now = (int)m[i];\r
325             if (!json.IsDefined("api_slot_item"))\r
326                 return;\r
327             InspectSlotItem(json.api_slot_item);\r
328         }\r
329 \r
330         public void InspectGetShip(dynamic json)\r
331         {\r
332             NowShips += 1;\r
333             if (json.api_slotitem == null) // まるゆにはスロットがない\r
334                 return;\r
335             InspectSlotItem(json.api_slotitem);\r
336         }\r
337 \r
338         public void InspectDestroyItem(string request, dynamic json)\r
339         {\r
340             var values = HttpUtility.ParseQueryString(request);\r
341             DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray());\r
342             var get = (int[])json.api_get_material;\r
343             for (var i = 0; i < get.Length; i++)\r
344                 MaterialHistory[i].Now += get[i];\r
345         }\r
346 \r
347         public void InspectRemodelSlot(dynamic json)\r
348         {\r
349             var after = (int[])json.api_after_material;\r
350             for (var i = 0; i < after.Length; i++)\r
351                 MaterialHistory[i].Now = after[i];\r
352             if (json.api_after_slot())\r
353                 InspectSlotItem(json.api_after_slot);\r
354             if (!json.api_use_slot_id())\r
355                 return;\r
356             DeleteItems(((int[])json.api_use_slot_id));\r
357         }\r
358 \r
359         public void DeleteItems(int[] ids)\r
360         {\r
361             foreach (var id in ids.Where(id => id != -1))\r
362             {\r
363                 _itemInfo.Remove(id);\r
364                 NowEquips--;\r
365             }\r
366         }\r
367 \r
368         public void CountNewItems(int[] ids)\r
369         {\r
370             foreach (var id in ids.Where(id => id != -1 && !_itemInfo.ContainsKey(id)))\r
371             {\r
372                 _itemInfo[id] = new ItemStatus();\r
373                 NowEquips++;\r
374             }\r
375         }\r
376 \r
377         public void InspectMissionResult(dynamic json)\r
378         {\r
379             if ((int)json.api_clear_result == 0) // 失敗\r
380                 return;\r
381             var get = (int[])json.api_get_material;\r
382             for (var i = 0; i < get.Length; i++)\r
383                 MaterialHistory[i].Now += get[i];\r
384         }\r
385 \r
386         public ItemSpec this[int id] => GetSpecById(id);\r
387 \r
388         public ItemSpec GetSpecById(int id) => _itemInfo[id].Spec;\r
389 \r
390         public ItemSpec GetSpecByItemId(int id) => _itemSpecs[id];\r
391 \r
392         public Dictionary<int, ItemStatus> ItemDict => _itemInfo;\r
393 \r
394         public void SetItemOwner(ShipStatus[] shipList)\r
395         {\r
396             foreach (var e in _itemInfo)\r
397                 e.Value.Ship = new ShipStatus();\r
398             foreach (var s in shipList)\r
399             {\r
400                 foreach (var id in s.Slot)\r
401                     _itemInfo[id].Ship = s;\r
402             }\r
403         }\r
404 \r
405         public void SaveState(Status status)\r
406         {\r
407             NeedSave = false;\r
408             status.MatreialHistory = MaterialHistory;\r
409         }\r
410 \r
411         public void LoadState(Status status)\r
412         {\r
413             status.MatreialHistory?.CopyTo(MaterialHistory, 0);\r
414         }\r
415     }\r
416 \r
417     public enum Material\r
418     {\r
419         Fuel,\r
420         Bullet,\r
421         Steal,\r
422         Bouxite,\r
423         Burner,\r
424         Bucket,\r
425         Development,\r
426         Screw,\r
427     }\r
428 \r
429     public class MaterialCount\r
430     {\r
431         private int _now;\r
432 \r
433         public int BegOfDay { get; set; }\r
434         public int BegOfWeek { get; set; }\r
435         public DateTime LastSet { get; set; }\r
436         public bool NeedSave { get; set; }\r
437 \r
438         public int Now\r
439         {\r
440             get { return _now; }\r
441             set\r
442             {\r
443                 var prev = _now;\r
444                 _now = value;\r
445                 if (Status.Restoring) // JSONから値を復旧するときは履歴に触らない\r
446                     return;\r
447                 if (_now != prev)\r
448                     NeedSave = true;\r
449                 if (LastSet == DateTime.MinValue)\r
450                 {\r
451                     BegOfDay = BegOfWeek = value;\r
452                     LastSet = DateTime.Now;\r
453                     return;\r
454                 }\r
455                 UpdateHistory(prev);\r
456                 LastSet = DateTime.Now;\r
457             }\r
458         }\r
459 \r
460         private void UpdateHistory(int prev)\r
461         {\r
462             var morning = DateTime.Today.AddHours(5);\r
463             var dow = (int)morning.DayOfWeek;\r
464             var monday = morning.AddDays(dow == 0 ? -6 : -dow + 1);\r
465             if (DateTime.Now >= morning && LastSet < morning)\r
466                 BegOfDay = prev;\r
467             if (DateTime.Now >= monday && LastSet < monday)\r
468                 BegOfWeek = prev;\r
469         }\r
470     }\r
471 }