// Copyright (C) 2013, 2014, 2015 Kazuhiro Fujieda // // This program is part of KancolleSniffer. // // KancolleSniffer is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, see . using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Web; namespace KancolleSniffer { public class ItemSpec { public int Id; public string Name; public int Type; public string TypeName; public int IconType; public int AntiAir; public int LoS; public int AntiSubmarine; public int Torpedo; public int Bomber; public ItemSpec() { Id = -1; Name = ""; } public bool CanAirCombat { get { switch (Type) { case 6: // 艦戦 case 7: // 艦爆 case 8: // 艦攻 case 11: // 水爆 return true; } return false; } } // http://ch.nicovideo.jp/biikame/blomaga/ar663428 public double LoSScaleFactor() { switch (Type) { case 7: // 艦爆 return 1.0376255; case 8: // 艦攻 return 1.3677954; case 9: // 艦偵 return 1.6592780; case 10: // 水偵 return 2.0000000; case 11: // 水爆 return 1.7787282; case 12: // 小型電探 return 1.0045358; case 13: // 大型電探 return 0.9906638; } if (Name == "探照灯") return 0.9067950; return 0; } public bool IsAircraft { get { switch (Type) { case 6: case 7: case 8: case 9: case 10: case 11: case 25: // オートジャイロ case 26: // 対潜哨戒機 return true; } return false; } } public bool IsSonar => Type == 14 || // ソナー Type == 40; // 大型ソナー public bool IsDepthCharge => Type == 15; public bool IsReconSeaplane => Type == 10; public Color Color { get { switch (IconType) { case 1: case 2: case 3: // 主砲 case 13: // 徹甲弾 return Color.FromArgb(209, 89, 89); case 4: // 副砲 return Color.FromArgb(253, 233, 0); case 5: // 魚雷 return Color.FromArgb(88, 134, 170); case 6: // 艦戦 return Color.FromArgb(93, 179, 108); case 7: // 艦爆 return Color.FromArgb(223, 102, 102); case 8: // 艦攻 return Color.FromArgb(95, 173, 234); case 9: // 艦偵 return Color.FromArgb(254, 191, 0); case 10: // 水上機 return Color.FromArgb(142, 203, 152); case 11: // 電探 return Color.FromArgb(231, 153, 53); case 12: // 三式弾 return Color.FromArgb(69, 175, 88); case 14: // 応急修理要員 return Color.FromArgb(254, 254, 254); case 15: // 機銃 case 16: // 高角砲 return Color.FromArgb(102, 204, 118); case 17: // 爆雷 case 18: // ソナー return Color.FromArgb(126, 203, 215); case 19: // 缶 return Color.FromArgb(254, 195, 77); case 20: // 大発 return Color.FromArgb(154, 163, 90); case 21: // オートジャイロ return Color.FromArgb(99, 203, 115); case 22: // 対潜哨戒機 return Color.FromArgb(125, 205, 217); case 23: // 追加装甲 return Color.FromArgb(152, 124, 172); case 24: // 探照灯 case 27: // 照明弾 return Color.FromArgb(254, 155, 0); case 25: // ドラム缶 return Color.FromArgb(161, 161, 160); case 26: // 艦艇修理施設 return Color.FromArgb(175, 156, 126); case 28: // 司令部施設 return Color.FromArgb(204, 172, 252); case 29: // 航空要員 return Color.FromArgb(206, 166, 108); case 30: // 高射装置 return Color.FromArgb(137, 153, 77); case 31: // 対地装備 return Color.FromArgb(253, 49, 49); case 32: // 水上艦要員 return Color.FromArgb(188, 238, 155); case 33: // 大型飛行艇 return Color.FromArgb(142, 203, 152); case 34: // 戦闘糧食 return Color.FromArgb(254, 254, 254); default: return SystemColors.Control; } } } } public class ItemStatus { public int Id { get; set; } public ItemSpec Spec { get; set; } = new ItemSpec(); public int Level { get; set; } public int Alv { get; set; } public ShipStatus Ship { get; set; } public ItemStatus() { Id = -1; } public ItemStatus(int id) { Id = id == 0 ? -1 : id; } public int AlvBonus { get { if (Alv != 7) return 0; switch (Spec.Type) { case 6: // 艦戦 return 25; case 7: // 艦爆 return 3; case 8: // 艦攻 return 3; case 11: // 水爆 return 9; } return 0; } } } public class ItemInfo { private int _nowShips, _nowEquips; private readonly Dictionary _itemSpecs = new Dictionary(); private readonly Dictionary _itemInfo = new Dictionary(); private readonly Dictionary _useItemName = new Dictionary(); public int MaxShips { get; private set; } public int MarginShips { get; set; } public bool RingShips { get; set; } public int MaxEquips { get; private set; } public int MarginEquips { get; set; } public bool RingEquips { get; set; } public int NowShips { get { return _nowShips; } set { if (MaxShips != 0) { var limit = MaxShips - MarginShips; RingShips = _nowShips < limit && value >= limit; } _nowShips = value; } } public bool TooManyShips => MaxShips != 0 && NowShips >= MaxShips - MarginShips; public int NowEquips { get { return _nowEquips; } private set { if (MaxEquips != 0) { var limit = MaxEquips - MarginEquips; RingEquips = _nowEquips < limit && value >= limit; } _nowEquips = value; } } public bool TooManyEquips => MaxEquips != 0 && NowEquips >= MaxEquips - MarginEquips; public ItemInfo() { MarginShips = 4; MarginEquips = 10; } public void InspectBasic(dynamic json) { MaxShips = (int)json.api_max_chara; MaxEquips = (int)json.api_max_slotitem; } public void InspectMaster(dynamic json) { var dict = new Dictionary(); foreach (var entry in json.api_mst_slotitem_equiptype) dict[(int)entry.api_id] = entry.api_name; foreach (var entry in json.api_mst_slotitem) { _itemSpecs[(int)entry.api_id] = new ItemSpec { Id = (int)entry.api_id, Name = (string)entry.api_name, Type = (int)entry.api_type[2], TypeName = dict[(int)entry.api_type[2]], IconType = (int)entry.api_type[3], AntiAir = (int)entry.api_tyku, LoS = (int)entry.api_saku, AntiSubmarine = (int)entry.api_tais, Torpedo = (int)entry.api_raig, Bomber = (int)entry.api_baku }; } _itemSpecs[-1] = new ItemSpec(); foreach (var entry in json.api_mst_useitem) _useItemName[(int)entry.api_id] = entry.api_name; } public void InspectSlotItem(dynamic json, bool full = false) { if (!json.IsArray) json = new[] {json}; if (full) { _itemInfo.Clear(); _itemInfo[-1] = new ItemStatus(); } foreach (var entry in json) { var id = (int)entry.api_id; _itemInfo[id] = new ItemStatus(id) { Spec = _itemSpecs[(int)entry.api_slotitem_id], Level = entry.api_level() ? (int)entry.api_level : 0, Alv = entry.api_alv() ? (int)entry.api_alv : 0 }; } NowEquips = _itemInfo.Count - 1; } public void InspectCreateItem(dynamic json) { if (!json.IsDefined("api_slot_item")) return; InspectSlotItem(json.api_slot_item); } public void InspectGetShip(dynamic json) { NowShips += 1; if (json.api_slotitem == null) // まるゆにはスロットがない return; InspectSlotItem(json.api_slotitem); } public void InspectDestroyItem(string request, dynamic json) { var values = HttpUtility.ParseQueryString(request); DeleteItems(values["api_slotitem_ids"].Split(',').Select(int.Parse).ToArray()); } public void InspectRemodelSlot(dynamic json) { if (json.api_after_slot()) InspectSlotItem(json.api_after_slot); if (!json.api_use_slot_id()) return; DeleteItems(((int[])json.api_use_slot_id)); } public void DeleteItems(ItemStatus[] items) { DeleteItems(items.Select(item => item.Id)); } private void DeleteItems(IEnumerable ids) { foreach (var id in ids.Where(id => id != -1)) { _itemInfo.Remove(id); NowEquips--; } } public void CountNewItems(int[] ids) { foreach (var id in ids.Where(id => id != -1 && !_itemInfo.ContainsKey(id))) { _itemInfo[id] = new ItemStatus(); NowEquips++; } } public string GetName(int id) => _itemInfo[id].Spec.Name; public int GetItemId(int id) => _itemInfo[id].Spec.Id; public ItemSpec GetSpecByItemId(int id) => _itemSpecs[id]; public ItemStatus GetStatus(int id) => _itemInfo[id]; public ItemStatus[] GetItemListWithOwner(ShipStatus[] shipList) { foreach (var e in _itemInfo) e.Value.Ship = new ShipStatus(); foreach (var s in shipList) { foreach (var id in s.Slot) _itemInfo[id.Id].Ship = s; _itemInfo[s.SlotEx.Id].Ship = s; } return (from e in _itemInfo where e.Key != -1 select e.Value).ToArray(); } public string GetUseItemName(int id) => _useItemName[id]; } }