1 // Copyright (C) 2013, 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>
\r
3 // This program is part of KancolleSniffer.
\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
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
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
19 using System.Collections.Generic;
\r
23 namespace KancolleSniffer
\r
25 public class ShipStatus
\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
40 public struct ChargeStatus
\r
42 public int Fuel { get; set; }
\r
43 public int Bull { get; set; }
\r
46 public class ShipInfo
\r
48 private readonly int[][] _decks = new int[4][];
\r
49 private readonly Dictionary<int, ShipStatus> _shipInfo = new Dictionary<int, ShipStatus>();
\r
50 private readonly DateTime[][] _recoveryTimes = {new DateTime[3], new DateTime[3], new DateTime[3], new DateTime[3]};
\r
51 private readonly ShipMaster _shipMaster;
\r
52 private readonly ItemInfo _itemInfo;
\r
54 public ShipInfo(ShipMaster shipMaster, ItemInfo itemInfo)
\r
56 _shipMaster = shipMaster;
\r
57 _itemInfo = itemInfo;
\r
59 for (var i = 0; i < _decks.Length; i++)
\r
60 _decks[i] = new[] {-1, -1, -1, -1, -1, -1};
\r
63 public DateTime[] GetRecoveryTimes(int fleet)
\r
65 return _recoveryTimes[fleet];
\r
68 public void InspectShip(dynamic json)
\r
70 if (json.api_deck_port()) // port
\r
72 InspectShipData(json.api_ship);
\r
73 InspectDeck(json.api_deck_port);
\r
74 _itemInfo.NowShips = ((object[])json.api_ship).Length;
\r
76 else if (json.api_data()) // ship2
\r
78 InspectShipData(json.api_data);
\r
79 InspectDeck(json.api_data_deck);
\r
80 _itemInfo.NowShips = ((object[])json.api_data).Length;
\r
82 else if (json.api_ship_data()) // ship3
\r
84 // 一隻分のデータしか来ないことがあるので艦娘数を数えない
\r
85 InspectShipData(json.api_ship_data);
\r
86 InspectDeck(json.api_deck_data);
\r
88 else if (json.api_ship()) // getship
\r
90 InspectShipData(new[] {json.api_ship});
\r
94 private void InspectDeck(dynamic json)
\r
96 foreach (var entry in json)
\r
98 var fleet = (int)entry.api_id;
\r
99 var deck = _decks[fleet - 1];
\r
100 for (var i = 0; i < deck.Length; i++)
\r
101 deck[i] = (int)entry.api_ship[i];
\r
105 private void InspectShipData(dynamic json)
\r
108 json = new[] {json};
\r
109 foreach (var entry in json)
\r
111 _shipInfo[(int)entry.api_id] = new ShipStatus
\r
113 ShipId = (int)entry.api_ship_id,
\r
114 Name = _shipMaster[(int)entry.api_ship_id].Name,
\r
115 Level = (int)entry.api_lv,
\r
116 ExpToNext = (int)entry.api_exp[1],
\r
117 MaxHp = (int)entry.api_maxhp,
\r
118 NowHp = (int)entry.api_nowhp,
\r
119 Cond = (int)entry.api_cond,
\r
120 Fuel = (int)entry.api_fuel,
\r
121 Bull = (int)entry.api_bull,
\r
122 OnSlot = (from num in (dynamic[])entry.api_onslot select (int)num).ToArray(),
\r
123 Slot = (from num in (dynamic[])entry.api_slot select (int)num).ToArray()
\r
129 public void InspectCharge(dynamic json)
\r
131 foreach (var entry in json.api_ship)
\r
133 var status = _shipInfo[(int)entry.api_id];
\r
134 status.Bull = (int)entry.api_bull;
\r
135 status.Fuel = (int)entry.api_fuel;
\r
136 status.OnSlot = (from num in (dynamic[])entry.api_onslot select (int)num).ToArray();
\r
140 public void InspectChange(string request)
\r
142 var values = HttpUtility.ParseQueryString(request);
\r
143 var fleet = int.Parse(values["api_id"]) - 1;
\r
144 var idx = int.Parse(values["api_ship_idx"]);
\r
145 var ship = int.Parse(values["api_ship_id"]);
\r
148 var deck = _decks[fleet];
\r
149 for (var i = 1; i < deck.Length; i++)
\r
155 RemoveShip(fleet, idx);
\r
158 for (var f = 0; f < _decks.Length; f++)
\r
159 for (var i = 0; i < _decks[f].Length; i++)
\r
160 if (_decks[f][i] == ship) // 入れ替えの場合
\r
162 if ((_decks[f][i] = _decks[fleet][idx]) == -1)
\r
167 _decks[fleet][idx] = ship;
\r
170 private void RemoveShip(int fleet, int idx)
\r
172 var deck = _decks[fleet];
\r
173 for (var i = idx; i < deck.Length - 1; i++)
\r
174 deck[i] = deck[i + 1];
\r
175 deck[deck.Length - 1] = -1;
\r
178 public void InspectPowerup(string request, dynamic json)
\r
180 var values = HttpUtility.ParseQueryString(request);
\r
181 var ships = values["api_id_items"].Split(',');
\r
182 _itemInfo.NowShips -= ships.Length;
\r
183 _itemInfo.NowItems -= (from s in ships select SlotItemCount(int.Parse(s))).Sum();
\r
184 InspectDeck(json.api_deck);
\r
185 InspectShip(json.api_ship);
\r
188 public void InspectDestroyShip(string request)
\r
190 var values = HttpUtility.ParseQueryString(request);
\r
191 var id = int.Parse(values["api_ship_id"]);
\r
192 _itemInfo.NowShips -= 1;
\r
193 _itemInfo.NowItems -= SlotItemCount(id);
\r
194 foreach (var deck in _decks)
\r
196 for (var i = 0; i < deck.Length; i++)
\r
199 for (var j = i; j < deck.Length - 1; j++)
\r
200 deck[j] = deck[j + 1];
\r
201 deck[deck.Length - 1] = -1;
\r
206 public void InspectNyukyo(string request)
\r
208 var values = HttpUtility.ParseQueryString(request);
\r
209 var id = int.Parse(values["api_ship_id"]);
\r
210 if (int.Parse(values["api_highspeed"]) == 0)
\r
212 var ship = _shipInfo[id];
\r
213 ship.NowHp = ship.MaxHp;
\r
214 if (ship.Cond < 40)
\r
216 _itemInfo.NumBuckets--;
\r
219 private int SlotItemCount(int id)
\r
221 return _shipInfo[id].Slot.Count(item => item != -1);
\r
224 private void SetRecoveryTime()
\r
226 for (var fleet = 0; fleet < 4; fleet++)
\r
229 (from id in _decks[fleet] where _shipInfo.ContainsKey(id) select _shipInfo[id].Cond).DefaultIfEmpty(49)
\r
231 if (cond < 49 && _recoveryTimes[fleet][2] != DateTime.MinValue) // 計時中
\r
233 // コンディション値から推定される残り時刻と経過時間の差
\r
234 var diff = TimeSpan.FromMinutes((49 - cond + 2) / 3 * 3) - (_recoveryTimes[fleet][2] - DateTime.Now);
\r
235 if (diff >= TimeSpan.Zero && diff <= TimeSpan.FromMinutes(3)) // 差が0以上3分以内ならタイマーを更新しない。
\r
238 var thresh = new[] {30, 40, 49};
\r
239 for (var i = 0; i < thresh.Length; i++)
\r
240 _recoveryTimes[fleet][i] = cond < thresh[i]
\r
241 ? DateTime.Now.AddMinutes((thresh[i] - cond + 2) / 3 * 3)
\r
242 : DateTime.MinValue;
\r
246 public ShipStatus[] GetShipStatuses(int fleet)
\r
248 return _decks[fleet].Select(id => (id == -1) ? new ShipStatus() : _shipInfo[id]).ToArray();
\r
251 public ShipStatus this[int idx]
\r
253 get { return _shipInfo[idx]; }
\r
256 public ChargeStatus[] ChargeStatuses
\r
260 return (from deck in _decks
\r
261 select (from id in deck
\r
263 let status = _shipInfo[id]
\r
264 let spec = _shipMaster[status.ShipId]
\r
265 select new {status.Bull, status.Fuel, spec.BullMax, spec.FuelMax})
\r
267 new ChargeStatus(), (result, next) => new ChargeStatus()
\r
269 Bull = Math.Max(result.Bull, CalcChargeState(next.Bull, next.BullMax)),
\r
270 Fuel = Math.Max(result.Fuel, CalcChargeState(next.Fuel, next.FuelMax))
\r
275 private int CalcChargeState(int now, int full)
\r
277 if (full == 0 || now == full)
\r
279 var ratio = (double)now / full;
\r
280 if (ratio >= 7.0 / 9)
\r
282 if (ratio >= 3.0 / 9)
\r
289 public int GetAirSuperiority(int fleet)
\r
291 return (from id in _decks[fleet]
\r
292 where _shipInfo.ContainsKey(id)
\r
293 let ship = _shipInfo[id]
\r
294 from slot in ship.Slot.Zip(ship.OnSlot, (s, o) => new {slot = s, onslot = o})
\r
295 select (int)Math.Floor(_itemInfo.GetTyKu(slot.slot) * Math.Sqrt(slot.onslot))).Sum();
\r