OSDN Git Service

母港に戻ったときに必要ならstatus.jsonを保存する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ItemInfo.cs
1 // Copyright (C) 2013, 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\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.Linq;\r
21 using System.Web;\r
22 \r
23 namespace KancolleSniffer\r
24 {\r
25     public class ItemSpec\r
26     {\r
27         public int Id;\r
28         public string Name;\r
29         public int Type;\r
30         public string TypeName;\r
31         public int AntiAir;\r
32         public int LoS;\r
33 \r
34         public ItemSpec()\r
35         {\r
36             Id = -1;\r
37             Name = "";\r
38         }\r
39 \r
40         public bool CanAirCombat()\r
41         {\r
42             switch (Type)\r
43             {\r
44                 case 6: // 艦戦\r
45                 case 7: // 艦爆\r
46                 case 8: // 艦攻\r
47                 case 11: // 水爆\r
48                     return true;\r
49             }\r
50             return false;\r
51         }\r
52 \r
53         // http://ch.nicovideo.jp/biikame/blomaga/ar663428\r
54         public double LoSScaleFactor()\r
55         {\r
56             switch (Type)\r
57             {\r
58                 case 7: // 艦爆\r
59                     return 1.0376255;\r
60                 case 8: // 艦攻\r
61                     return 1.3677954;\r
62                 case 9: // 艦偵\r
63                     return 1.6592780;\r
64                 case 10: // 水偵\r
65                     return 2.0000000;\r
66                 case 11: // 水爆\r
67                     return 1.7787282;\r
68                 case 12: // 小型電探\r
69                     return 1.0045358;\r
70                 case 13: // 大型電探\r
71                     return 0.9906638;\r
72             }\r
73             if (Name == "探照灯")\r
74                 return 0.9067950;\r
75             return 0;\r
76         }\r
77     }\r
78 \r
79     public class ItemStatus\r
80     {\r
81         public ItemSpec Spec { get; set; }\r
82         public int Level { get; set; }\r
83         public ShipStatus Ship { get; set; }\r
84 \r
85         public ItemStatus()\r
86         {\r
87             Spec = new ItemSpec();\r
88             Ship = new ShipStatus();\r
89         }\r
90     }\r
91 \r
92     public class ItemInfo\r
93     {\r
94         private int _nowShips, _nowEquips;\r
95         private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();\r
96         private readonly Dictionary<int, ItemStatus> _itemInfo = new Dictionary<int, ItemStatus>();\r
97 \r
98         public int MaxShips { get; private set; }\r
99         public int MarginShips { get; set; }\r
100         public bool RingShips { get; set; }\r
101         public int MaxEquips { get; private set; }\r
102         public int MarginEquips { get; set; }\r
103         public bool RingEquips { get; set; }\r
104         public MaterialCount[] MaterialHistory { get; private set; }\r
105 \r
106         public bool NeedSave\r
107         {\r
108             get { return MaterialHistory.Any(m => m.NeedSave); }\r
109             private set\r
110             {\r
111                 foreach (var m in MaterialHistory)\r
112                     m.NeedSave = value;\r
113             }\r
114         }\r
115 \r
116         public int NowShips\r
117         {\r
118             get { return _nowShips; }\r
119             set\r
120             {\r
121                 if (MaxShips != 0)\r
122                 {\r
123                     var limit = MaxShips - MarginShips;\r
124                     RingShips = _nowShips < limit && value >= limit;\r
125                 }\r
126                 _nowShips = value;\r
127             }\r
128         }\r
129 \r
130         public bool TooManyShips\r
131         {\r
132             get { return MaxShips != 0 && NowShips >= MaxShips - MarginShips; }\r
133         }\r
134 \r
135         public int NowEquips\r
136         {\r
137             get { return _nowEquips; }\r
138             private set\r
139             {\r
140                 if (MaxEquips != 0)\r
141                 {\r
142                     var limit = MaxEquips - MarginEquips;\r
143                     RingEquips = _nowEquips < limit && value >= limit;\r
144                 }\r
145                 _nowEquips = value;\r
146             }\r
147         }\r
148 \r
149         public bool TooManyEquips\r
150         {\r
151             get { return MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips; }\r
152         }\r
153 \r
154         public ItemInfo()\r
155         {\r
156             MaterialHistory = new MaterialCount[Enum.GetValues(typeof (Material)).Length];\r
157             foreach (Material m in Enum.GetValues(typeof (Material)))\r
158                 MaterialHistory[(int)m] = new MaterialCount();\r
159             MarginShips = 4;\r
160             MarginEquips = 10;\r
161         }\r
162 \r
163         public void InspectBasic(dynamic json)\r
164         {\r
165             MaxShips = (int)json.api_max_chara;\r
166             MaxEquips = (int)json.api_max_slotitem;\r
167         }\r
168 \r
169         public void InspectMaterial(dynamic json)\r
170         {\r
171             foreach (var entry in json)\r
172                 MaterialHistory[(int)entry.api_id - 1].Now = (int)entry.api_value;\r
173         }\r
174 \r
175         public void InspectMaster(dynamic json)\r
176         {\r
177             var dict = new Dictionary<int, string>();\r
178             foreach (var entry in json.api_mst_slotitem_equiptype)\r
179                 dict[(int)entry.api_id] = entry.api_name;\r
180             foreach (var entry in json.api_mst_slotitem)\r
181             {\r
182                 _itemSpecs[(int)entry.api_id] = new ItemSpec\r
183                 {\r
184                     Id = (int)entry.api_id,\r
185                     Name = (string)entry.api_name,\r
186                     Type = (int)entry.api_type[2],\r
187                     TypeName = dict[(int)entry.api_type[2]],\r
188                     AntiAir = (int)entry.api_tyku,\r
189                     LoS = (int)entry.api_saku\r
190                 };\r
191             }\r
192             _itemSpecs[-1] = new ItemSpec();\r
193         }\r
194 \r
195         public void InspectSlotItem(dynamic json, bool full = false)\r
196         {\r
197             if (!json.IsArray)\r
198                 json = new[] {json};\r
199             if (full)\r
200             {\r
201                 _itemInfo.Clear();\r
202                 _itemInfo[-1] = new ItemStatus();\r
203             }\r
204             foreach (var entry in json)\r
205             {\r
206                 _itemInfo[(int)entry.api_id] = new ItemStatus\r
207                 {\r
208                     Spec = _itemSpecs[(int)entry.api_slotitem_id],\r
209                     Level = entry.api_level() ? (int)entry.api_level : 0\r
210                 };\r
211             }\r
212             NowEquips = _itemInfo.Count - 1;\r
213         }\r
214 \r
215         public void InspectCreateItem(dynamic json)\r
216         {\r
217             var m = (dynamic[])json.api_material;\r
218             for (var i = 0; i < m.Length; i++)\r
219                 MaterialHistory[i].Now = (int)m[i];\r
220             if (!json.IsDefined("api_slot_item"))\r
221                 return;\r
222             InspectSlotItem(json.api_slot_item);\r
223         }\r
224 \r
225         public void InspectGetShip(dynamic json)\r
226         {\r
227             NowShips += 1;\r
228             if (json.api_slotitem == null) // まるゆにはスロットがない\r
229                 return;\r
230             InspectSlotItem(json.api_slotitem);\r
231         }\r
232 \r
233         public void InspectDestroyItem(string request, dynamic json)\r
234         {\r
235             var values = HttpUtility.ParseQueryString(request);\r
236             DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray());\r
237             var get = (int[])json.api_get_material;\r
238             for (var i = 0; i < get.Length; i++)\r
239                 MaterialHistory[i].Now += get[i];\r
240         }\r
241 \r
242         public void InspectRemodelSlot(dynamic json)\r
243         {\r
244             if (json.api_after_slot())\r
245                 InspectSlotItem(json.api_after_slot);\r
246             if (!json.api_use_slot_id())\r
247                 return;\r
248             DeleteItems(((int[])json.api_use_slot_id));\r
249         }\r
250 \r
251         public void DeleteItems(int[] ids)\r
252         {\r
253             foreach (var id in ids.Where(id => id != -1))\r
254             {\r
255                 _itemInfo.Remove(id);\r
256                 NowEquips--;\r
257             }\r
258         }\r
259 \r
260         public void CountNewItems(int[] ids)\r
261         {\r
262             foreach (var id in ids.Where(id => id != -1 && !_itemInfo.ContainsKey(id)))\r
263             {\r
264                 _itemInfo[id] = new ItemStatus();\r
265                 NowEquips++;\r
266             }\r
267         }\r
268 \r
269         public void InspectMissionResult(dynamic json)\r
270         {\r
271             if ((int)json.api_clear_result == 0) // 失敗\r
272                 return;\r
273             var get = (int[])json.api_get_material;\r
274             for (var i = 0; i < get.Length; i++)\r
275                 MaterialHistory[i].Now += get[i];\r
276         }\r
277 \r
278         public ItemSpec this[int id]\r
279         {\r
280             get { return GetSpecById(id); }\r
281         }\r
282 \r
283         public ItemSpec GetSpecById(int id)\r
284         {\r
285             return _itemInfo[id].Spec;\r
286         }\r
287 \r
288         public ItemSpec GetSpecByItemId(int id)\r
289         {\r
290             return _itemSpecs[id];\r
291         }\r
292 \r
293         public ItemStatus[] GetItemList(ShipInfo ship)\r
294         {\r
295             foreach (var e in _itemInfo)\r
296                 e.Value.Ship = new ShipStatus();\r
297             foreach (var s in ship.ShipList)\r
298             {\r
299                 foreach (var id in s.Slot)\r
300                     _itemInfo[id].Ship = s;\r
301             }\r
302             return _itemInfo.Where(e => e.Key != -1).Select(e => e.Value).ToArray();\r
303         }\r
304 \r
305         public void SaveState(Status status)\r
306         {\r
307             NeedSave = false;\r
308             status.MatreialHistory = MaterialHistory;\r
309         }\r
310 \r
311         public void LoadSate(Status status)\r
312         {\r
313             if (status.MatreialHistory != null)\r
314                 status.MatreialHistory.CopyTo(MaterialHistory, 0);\r
315         }\r
316     }\r
317 \r
318     public enum Material\r
319     {\r
320         Fuel,\r
321         Bullet,\r
322         Steal,\r
323         Bouxite,\r
324         Burner,\r
325         Bucket,\r
326         Development,\r
327         Screw,\r
328     }\r
329 \r
330     public class MaterialCount\r
331     {\r
332         private int _now;\r
333 \r
334         public int BegOfDay { get; set; }\r
335         public int BegOfWeek { get; set; }\r
336         public DateTime LastSet { get; set; }\r
337         public bool NeedSave { get; set; }\r
338 \r
339         public int Now\r
340         {\r
341             get { return _now; }\r
342             set\r
343             {\r
344                 var prev = _now;\r
345                 _now = value;\r
346                 if (Status.Restoring) // JSONから値を復旧するときは履歴に触らない\r
347                     return;\r
348                 if (LastSet == DateTime.MinValue)\r
349                 {\r
350                     BegOfDay = BegOfWeek = value;\r
351                     LastSet = DateTime.Now;\r
352                     NeedSave = true;\r
353                     return;\r
354                 }\r
355                 UpdateHistory(prev);\r
356                 LastSet = DateTime.Now;\r
357             }\r
358         }\r
359 \r
360         private void UpdateHistory(int prev)\r
361         {\r
362             var morning = DateTime.Today.AddHours(5);\r
363             var dow = (int)morning.DayOfWeek;\r
364             var monday = morning.AddDays(dow == 0 ? -6 : -dow + 1);\r
365             if (DateTime.Now >= morning && LastSet < morning)\r
366             {\r
367                 BegOfDay = prev;\r
368                 NeedSave = true;\r
369             }\r
370             if (DateTime.Now >= monday && LastSet < monday)\r
371             {\r
372                 BegOfWeek = prev;\r
373                 NeedSave = true;\r
374             }\r
375         }\r
376     }\r
377 }