OSDN Git Service

編成を入れ替えてから母港に戻るまで疲労タイマーを無効にする
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ShipInfo.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 ShipStatus\r
26     {\r
27         public int ShipId { get; set; }\r
28         public string Name { get; set; }\r
29         public int Level { get; set; }\r
30         public int ExpToNext { get; set; }\r
31         public int MaxHp { get; set; }\r
32         public int NowHp { get; set; }\r
33         public int Cond { get; set; }\r
34         public int Fuel { get; set; }\r
35         public int Bull { get; set; }\r
36         public int[] OnSlot { get; set; }\r
37         public int[] Slot { get; set; }\r
38 \r
39         public int DamageLevel\r
40         {\r
41             get\r
42             {\r
43                 var ratio = MaxHp == 0 ? 1 : (double)NowHp / MaxHp;\r
44                 return ratio > 0.75 ? 0 : ratio > 0.5 ? 1 : ratio > 0.25 ? 2 : 3;\r
45             }\r
46         }\r
47     }\r
48 \r
49     public struct ChargeStatus\r
50     {\r
51         public int Fuel { get; set; }\r
52         public int Bull { get; set; }\r
53     }\r
54 \r
55     public class ShipInfo\r
56     {\r
57         public const int FleetCount = 4;\r
58         public const int MemberCount = 6;\r
59 \r
60         private readonly int[][] _decks = new int[FleetCount][];\r
61         private readonly Dictionary<int, ShipStatus> _shipInfo = new Dictionary<int, ShipStatus>();\r
62         private readonly ConditionTimer _conditionTimer;\r
63 \r
64         private readonly ShipMaster _shipMaster;\r
65         private readonly ItemInfo _itemInfo;\r
66 \r
67         public ShipInfo(ShipMaster shipMaster, ItemInfo itemInfo)\r
68         {\r
69             _shipMaster = shipMaster;\r
70             _itemInfo = itemInfo;\r
71             _conditionTimer = new ConditionTimer(this);\r
72 \r
73             for (var fleet = 0; fleet < FleetCount; fleet++)\r
74             {\r
75                 var deck = new int[MemberCount];\r
76                 for (var i = 0; i < deck.Length; i++)\r
77                     deck[i] = -1;\r
78                 _decks[fleet] = deck;\r
79             }\r
80         }\r
81 \r
82         public void InspectShip(dynamic json)\r
83         {\r
84             if (json.api_deck_port()) // port\r
85             {\r
86                 InspectShipData(json.api_ship);\r
87                 InspectDeck(json.api_deck_port);\r
88                 _itemInfo.NowShips = ((object[])json.api_ship).Length;\r
89             }\r
90             else if (json.api_data()) // ship2\r
91             {\r
92                 InspectShipData(json.api_data);\r
93                 InspectDeck(json.api_data_deck);\r
94                 _itemInfo.NowShips = ((object[])json.api_data).Length;\r
95             }\r
96             else if (json.api_ship_data()) // ship3\r
97             {\r
98                 // 一隻分のデータしか来ないことがあるので艦娘数を数えない\r
99                 InspectShipData(json.api_ship_data);\r
100                 InspectDeck(json.api_deck_data);\r
101             }\r
102             else if (json.api_ship()) // getship\r
103             {\r
104                 InspectShipData(new[] {json.api_ship});\r
105             }\r
106         }\r
107 \r
108         private void InspectDeck(dynamic json)\r
109         {\r
110             foreach (var entry in json)\r
111             {\r
112                 var fleet = (int)entry.api_id - 1;\r
113                 var deck = _decks[fleet];\r
114                 for (var i = 0; i < deck.Length; i++)\r
115                     deck[i] = (int)entry.api_ship[i];\r
116             }\r
117         }\r
118 \r
119         private void InspectShipData(dynamic json)\r
120         {\r
121             foreach (var entry in json)\r
122             {\r
123                 _shipInfo[(int)entry.api_id] = new ShipStatus\r
124                 {\r
125                     ShipId = (int)entry.api_ship_id,\r
126                     Name = _shipMaster[(int)entry.api_ship_id].Name,\r
127                     Level = (int)entry.api_lv,\r
128                     ExpToNext = (int)entry.api_exp[1],\r
129                     MaxHp = (int)entry.api_maxhp,\r
130                     NowHp = (int)entry.api_nowhp,\r
131                     Cond = (int)entry.api_cond,\r
132                     Fuel = (int)entry.api_fuel,\r
133                     Bull = (int)entry.api_bull,\r
134                     OnSlot = (from num in (dynamic[])entry.api_onslot select (int)num).ToArray(),\r
135                     Slot = (from num in (dynamic[])entry.api_slot select (int)num).ToArray()\r
136                 };\r
137             }\r
138             _conditionTimer.SetTimer();\r
139         }\r
140 \r
141         public void InspectCharge(dynamic json)\r
142         {\r
143             foreach (var entry in json.api_ship)\r
144             {\r
145                 var status = _shipInfo[(int)entry.api_id];\r
146                 status.Bull = (int)entry.api_bull;\r
147                 status.Fuel = (int)entry.api_fuel;\r
148                 status.OnSlot = (from num in (dynamic[])entry.api_onslot select (int)num).ToArray();\r
149             }\r
150         }\r
151 \r
152         public void InspectChange(string request)\r
153         {\r
154             var values = HttpUtility.ParseQueryString(request);\r
155             var fleet = int.Parse(values["api_id"]) - 1;\r
156             var idx = int.Parse(values["api_ship_idx"]);\r
157             var ship = int.Parse(values["api_ship_id"]);\r
158             _conditionTimer.Disable(fleet);\r
159             if (idx == -1)\r
160             {\r
161                 var deck = _decks[fleet];\r
162                 for (var i = 1; i < deck.Length; i++)\r
163                     deck[i] = -1;\r
164                 return;\r
165             }\r
166             if (ship == -1)\r
167             {\r
168                 RemoveShip(fleet, idx);\r
169                 return;\r
170             }\r
171             AlterShip(ship, (f, i) =>\r
172             {\r
173                 // 入れ替えの場合\r
174                 if ((_decks[f][i] = _decks[fleet][idx]) == -1)\r
175                     RemoveShip(f, i);\r
176                 _conditionTimer.Disable(f);\r
177             });\r
178             _decks[fleet][idx] = ship;\r
179         }\r
180 \r
181         private void AlterShip(int ship, Action<int, int> action)\r
182         {\r
183             for (var f = 0; f < _decks.Length; f++)\r
184             {\r
185                 var i = Array.FindIndex(_decks[f], id => id == ship);\r
186                 if (i < 0)\r
187                     continue;\r
188                 action(f, i);\r
189                 return;\r
190             }\r
191         }\r
192 \r
193         private void RemoveShip(int fleet, int idx)\r
194         {\r
195             var deck = _decks[fleet];\r
196             for (var i = idx; i < deck.Length - 1; i++)\r
197                 deck[i] = deck[i + 1];\r
198             deck[deck.Length - 1] = -1;\r
199             _conditionTimer.Disable(fleet);\r
200         }\r
201 \r
202         public void InspectPowerup(string request, dynamic json)\r
203         {\r
204             var values = HttpUtility.ParseQueryString(request);\r
205             var ships = values["api_id_items"].Split(',');\r
206             _itemInfo.NowShips -= ships.Length;\r
207             _itemInfo.NowItems -= (from s in ships select SlotItemCount(int.Parse(s))).Sum();\r
208             InspectDeck(json.api_deck);\r
209             InspectShip(json.api_ship);\r
210         }\r
211 \r
212         public void InspectDestroyShip(string request)\r
213         {\r
214             var values = HttpUtility.ParseQueryString(request);\r
215             var ship = int.Parse(values["api_ship_id"]);\r
216             _itemInfo.NowShips -= 1;\r
217             _itemInfo.NowItems -= SlotItemCount(ship);\r
218             AlterShip(ship, RemoveShip);\r
219         }\r
220 \r
221         private int SlotItemCount(int id)\r
222         {\r
223             return _shipInfo[id].Slot.Count(item => item != -1);\r
224         }\r
225 \r
226         public void InspectNyukyo(string request)\r
227         {\r
228             var values = HttpUtility.ParseQueryString(request);\r
229             var id = int.Parse(values["api_ship_id"]);\r
230             if (int.Parse(values["api_highspeed"]) == 0)\r
231                 return;\r
232             var ship = _shipInfo[id];\r
233             ship.NowHp = ship.MaxHp;\r
234             if (ship.Cond < 40)\r
235                 ship.Cond = 40;\r
236             _itemInfo.NumBuckets--;\r
237         }\r
238 \r
239         public ShipStatus[] GetShipStatuses(int fleet)\r
240         {\r
241             return _decks[fleet].Select(id => (id == -1) ? new ShipStatus {Name = ""} : _shipInfo[id]).ToArray();\r
242         }\r
243 \r
244         public int[] GetDeck(int fleet)\r
245         {\r
246             return _decks[fleet];\r
247         }\r
248 \r
249         public ShipStatus this[int idx]\r
250         {\r
251             get { return _shipInfo[idx]; }\r
252         }\r
253 \r
254         public string[] GetConditionTimers(int fleet)\r
255         {\r
256             return _conditionTimer.GetTimerStrings(fleet);\r
257         }\r
258 \r
259         public ChargeStatus[] ChargeStatuses\r
260         {\r
261             get\r
262             {\r
263                 return (from deck in _decks\r
264                     select (from id in deck\r
265                         where id != -1\r
266                         let status = _shipInfo[id]\r
267                         let spec = _shipMaster[status.ShipId]\r
268                         select new {status.Bull, status.Fuel, spec.BullMax, spec.FuelMax})\r
269                         .Aggregate(\r
270                             new ChargeStatus(), (result, next) => new ChargeStatus\r
271                             {\r
272                                 Bull = Math.Max(result.Bull, CalcChargeState(next.Bull, next.BullMax)),\r
273                                 Fuel = Math.Max(result.Fuel, CalcChargeState(next.Fuel, next.FuelMax))\r
274                             })).ToArray();\r
275             }\r
276         }\r
277 \r
278         private int CalcChargeState(int now, int full)\r
279         {\r
280             if (full == 0 || now == full)\r
281                 return 0;\r
282             var ratio = (double)now / full;\r
283             if (ratio >= 7.0 / 9)\r
284                 return 1;\r
285             if (ratio >= 3.0 / 9)\r
286                 return 2;\r
287             if (ratio > 0)\r
288                 return 3;\r
289             return 4;\r
290         }\r
291 \r
292         public int GetAirSuperiority(int fleet)\r
293         {\r
294             return (from id in _decks[fleet]\r
295                 where _shipInfo.ContainsKey(id)\r
296                 let ship = _shipInfo[id]\r
297                 from slot in ship.Slot.Zip(ship.OnSlot, (s, o) => new {slot = s, onslot = o})\r
298                 select (int)Math.Floor(_itemInfo[slot.slot].TyKu * Math.Sqrt(slot.onslot))).Sum();\r
299         }\r
300     }\r
301 }