OSDN Git Service

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