1 // Copyright (C) 2013, 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // Licensed under the Apache License, Version 2.0 (the "License");
\r
4 // you may not use this file except in compliance with the License.
\r
5 // You may obtain a copy of the License at
\r
7 // http://www.apache.org/licenses/LICENSE-2.0
\r
9 // Unless required by applicable law or agreed to in writing, software
\r
10 // distributed under the License is distributed on an "AS IS" BASIS,
\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 // See the License for the specific language governing permissions and
\r
13 // limitations under the License.
\r
15 using System.Collections.Generic;
\r
16 using System.Drawing;
\r
18 using static System.Math;
\r
20 namespace KancolleSniffer
\r
22 public class ItemSpec
\r
27 public string TypeName;
\r
28 public int IconType;
\r
31 public int AntiSubmarine;
\r
41 public bool CanAirCombat
\r
58 // http://ja.kancolle.wikia.com/wiki/%E3%83%9E%E3%83%83%E3%83%97%E7%B4%A2%E6%95%B5
\r
59 public double LoSScaleFactor
\r
79 public bool IsAircraft
\r
101 public int RealAntiSubmarine
\r
107 case 1: // 小口径(12.7cm連装高角砲(後期型))
\r
109 case 12: // 小型電探(22号対水上電探改四)
\r
113 return AntiSubmarine;
\r
118 public bool IsReconSeaplane => Type == 10;
\r
120 public bool IsSonar => Type == 14 || // ソナー
\r
121 Type == 40; // 大型ソナー
\r
123 public bool IsDepthCharge => Type == 15;
\r
125 public bool IsRepairFacility => Type == 31;
\r
127 public double ContactTriggerRate
\r
153 return Color.FromArgb(209, 89, 89);
\r
155 return Color.FromArgb(253, 233, 0);
\r
157 return Color.FromArgb(88, 134, 170);
\r
159 return Color.FromArgb(93, 179, 108);
\r
161 return Color.FromArgb(223, 102, 102);
\r
163 return Color.FromArgb(95, 173, 234);
\r
165 return Color.FromArgb(254, 191, 0);
\r
167 return Color.FromArgb(142, 203, 152);
\r
169 return Color.FromArgb(231, 153, 53);
\r
171 return Color.FromArgb(69, 175, 88);
\r
173 return Color.FromArgb(254, 254, 254);
\r
176 return Color.FromArgb(102, 204, 118);
\r
179 return Color.FromArgb(126, 203, 215);
\r
181 return Color.FromArgb(254, 195, 77);
\r
183 return Color.FromArgb(154, 163, 90);
\r
184 case 21: // オートジャイロ
\r
185 return Color.FromArgb(99, 203, 115);
\r
187 return Color.FromArgb(125, 205, 217);
\r
189 return Color.FromArgb(152, 124, 172);
\r
192 return Color.FromArgb(254, 155, 0);
\r
194 return Color.FromArgb(161, 161, 160);
\r
196 return Color.FromArgb(175, 156, 126);
\r
198 return Color.FromArgb(204, 172, 252);
\r
200 return Color.FromArgb(206, 166, 108);
\r
202 return Color.FromArgb(137, 153, 77);
\r
204 return Color.FromArgb(253, 49, 49);
\r
206 return Color.FromArgb(188, 238, 155);
\r
208 return Color.FromArgb(142, 203, 152);
\r
210 return Color.FromArgb(254, 254, 254);
\r
212 return SystemColors.Control;
\r
218 public class ItemStatus
\r
220 public int Id { get; set; }
\r
221 public ItemSpec Spec { get; set; } = new ItemSpec();
\r
222 public int Level { get; set; }
\r
223 public int Alv { get; set; }
\r
224 public ShipStatus Ship { get; set; }
\r
226 public ItemStatus()
\r
231 public ItemStatus(int id)
\r
233 Id = id == 0 ? -1 : id;
\r
236 private readonly double[] _alvBonusMin =
\r
238 Sqrt(0.0), Sqrt(1.0), Sqrt(2.5), Sqrt(4.0), Sqrt(5.5), Sqrt(7.0),
\r
239 Sqrt(8.5), Sqrt(10.0)
\r
242 private readonly double[] _alvBonusMax =
\r
244 Sqrt(0.9), Sqrt(2.4), Sqrt(3.9), Sqrt(5.4), Sqrt(6.9), Sqrt(8.4),
\r
245 Sqrt(9.9), Sqrt(12.0)
\r
248 private readonly Dictionary<int, int[]> _alvTypeBonus = new Dictionary<int, int[]>
\r
250 {06, new[] {0, 0, 2, 5, 9, 14, 14, 22}}, // 艦戦
\r
251 {07, new[] {0, 0, 0, 0, 0, 0, 0, 0}}, // 艦爆
\r
252 {08, new[] {0, 0, 0, 0, 0, 0, 0, 0}}, // 艦攻
\r
253 {11, new[] {0, 0, 1, 1, 1, 3, 3, 6}}, // 水爆
\r
254 {45, new[] {0, 0, 0, 0, 0, 0, 0, 0}} // 水戦
\r
257 public double[] AlvBonus
\r
262 if (!_alvTypeBonus.TryGetValue(Spec.Type, out table))
\r
263 return new[] {0.0, 0.0};
\r
264 return new[] {table[Alv] + _alvBonusMin[Alv], table[Alv] + _alvBonusMax[Alv]};
\r
268 public double LoSLevelBonus
\r
275 return 1.2 * Sqrt(Level);
\r
278 return 1.25 * Sqrt(Level);
\r
285 public double FirePowerLevelBonus
\r
293 return Sqrt(Level);
\r
295 return 1.5 * Sqrt(Level);
\r
297 return Sqrt(Level);
\r
300 return 0.75 * Sqrt(Level);
\r
302 return Sqrt(Level);
\r
309 public double TorpedoLevelBonus
\r
313 if (Spec.Type == 5) // 魚雷
\r
314 return 1.2 * Sqrt(Level);
\r
315 if (Spec.IconType == 15) // 機銃
\r
316 return 1.2 * Sqrt(Level);
\r
321 public double AntiSubmarineLevelBonus
\r
329 return Sqrt(Level);
\r
336 public double NightBattleLevelBonus
\r
345 return Sqrt(Level);
\r
347 return Spec.IconType == 15 ? 0 : Sqrt(Level);
\r
353 return Sqrt(Level);
\r
361 public class ItemInfo
\r
363 private int _nowShips, _nowEquips;
\r
364 private readonly Dictionary<int, ItemSpec> _itemSpecs = new Dictionary<int, ItemSpec>();
\r
365 private readonly Dictionary<int, ItemStatus> _itemInfo = new Dictionary<int, ItemStatus>();
\r
366 private readonly Dictionary<int, string> _useItemName = new Dictionary<int, string>();
\r
368 public int MaxShips { get; private set; }
\r
369 public int MarginShips { get; set; }
\r
370 public bool RingShips { get; set; }
\r
371 public int MaxEquips { get; private set; }
\r
372 public int MarginEquips { get; set; }
\r
373 public bool RingEquips { get; set; }
\r
375 public int NowShips
\r
377 get { return _nowShips; }
\r
382 var limit = MaxShips - MarginShips;
\r
383 RingShips = _nowShips < limit && value >= limit;
\r
389 public bool TooManyShips => MaxShips != 0 && NowShips >= MaxShips - MarginShips;
\r
391 public int NowEquips
\r
393 get { return _nowEquips; }
\r
396 if (MaxEquips != 0)
\r
398 var limit = MaxEquips - MarginEquips;
\r
399 RingEquips = _nowEquips < limit && value >= limit;
\r
401 _nowEquips = value;
\r
405 public bool TooManyEquips => MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips;
\r
413 public void InspectBasic(dynamic json)
\r
415 MaxShips = (int)json.api_max_chara;
\r
416 MaxEquips = (int)json.api_max_slotitem;
\r
419 public void InspectMaster(dynamic json)
\r
421 var dict = new Dictionary<int, string>();
\r
422 foreach (var entry in json.api_mst_slotitem_equiptype)
\r
423 dict[(int)entry.api_id] = entry.api_name;
\r
424 foreach (var entry in json.api_mst_slotitem)
\r
426 _itemSpecs[(int)entry.api_id] = new ItemSpec
\r
428 Id = (int)entry.api_id,
\r
429 Name = (string)entry.api_name,
\r
430 Type = (int)entry.api_type[2],
\r
431 TypeName = dict[(int)entry.api_type[2]],
\r
432 IconType = (int)entry.api_type[3],
\r
433 AntiAir = (int)entry.api_tyku,
\r
434 LoS = (int)entry.api_saku,
\r
435 AntiSubmarine = (int)entry.api_tais,
\r
436 Torpedo = (int)entry.api_raig,
\r
437 Bomber = (int)entry.api_baku
\r
440 _itemSpecs[-1] = new ItemSpec();
\r
441 foreach (var entry in json.api_mst_useitem)
\r
442 _useItemName[(int)entry.api_id] = entry.api_name;
\r
445 public void InspectSlotItem(dynamic json, bool full = false)
\r
448 json = new[] {json};
\r
452 _itemInfo[-1] = new ItemStatus();
\r
454 foreach (var entry in json)
\r
456 var id = (int)entry.api_id;
\r
457 _itemInfo[id] = new ItemStatus(id)
\r
459 Spec = _itemSpecs[(int)entry.api_slotitem_id],
\r
460 Level = entry.api_level() ? (int)entry.api_level : 0,
\r
461 Alv = entry.api_alv() ? (int)entry.api_alv : 0
\r
464 NowEquips = _itemInfo.Count - 1;
\r
467 public void InspectCreateItem(dynamic json)
\r
469 if (!json.IsDefined("api_slot_item"))
\r
471 InspectSlotItem(json.api_slot_item);
\r
474 public void InspectGetShip(dynamic json)
\r
477 if (json.api_slotitem == null) // まるゆにはスロットがない
\r
479 InspectSlotItem(json.api_slotitem);
\r
482 public void InspectDestroyItem(string request, dynamic json)
\r
484 var values = HttpUtility.ParseQueryString(request);
\r
485 DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray());
\r
488 public void InspectRemodelSlot(dynamic json)
\r
490 if (json.api_after_slot())
\r
491 InspectSlotItem(json.api_after_slot);
\r
492 if (!json.api_use_slot_id())
\r
494 DeleteItems(((int[])json.api_use_slot_id));
\r
497 public void DeleteItems(ItemStatus[] items)
\r
499 DeleteItems(items.Select(item => item.Id));
\r
502 private void DeleteItems(IEnumerable<int> ids)
\r
504 foreach (var id in ids.Where(id => id != -1))
\r
506 _itemInfo.Remove(id);
\r
511 public void CountNewItems(int[] ids)
\r
513 foreach (var id in ids.Where(id => id != -1 && !_itemInfo.ContainsKey(id)))
\r
515 _itemInfo[id] = new ItemStatus();
\r
520 public string GetName(int id) => _itemInfo[id].Spec.Name;
\r
522 public int GetItemId(int id) => _itemInfo[id].Spec.Id;
\r
524 public ItemSpec GetSpecByItemId(int id) => _itemSpecs[id];
\r
526 public ItemStatus GetStatus(int id) => _itemInfo[id];
\r
528 public ItemStatus[] GetItemListWithOwner(ShipStatus[] shipList)
\r
530 foreach (var e in _itemInfo)
\r
531 e.Value.Ship = new ShipStatus();
\r
532 foreach (var s in shipList)
\r
534 foreach (var id in s.Slot)
\r
535 _itemInfo[id.Id].Ship = s;
\r
536 _itemInfo[s.SlotEx.Id].Ship = s;
\r
538 return (from e in _itemInfo where e.Key != -1 select e.Value).ToArray();
\r
541 public string GetUseItemName(int id) => _useItemName[id];
\r