1 // Copyright (C) 2019 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
16 using System.Collections.Generic;
\r
17 using System.Drawing;
\r
19 using System.Windows.Forms;
\r
20 using KancolleSniffer.Model;
\r
22 namespace KancolleSniffer.View
\r
24 public class FleetSpec
\r
26 public static Record[] Create(Sniffer sniffer)
\r
28 var list = new List<Record>();
\r
29 foreach (var fleet in sniffer.Fleets)
\r
31 var shipRecords = new List<Record>();
\r
32 foreach (var ship in fleet.ActualShips)
\r
34 shipRecords.Add(Record.CreateShipRecord(ship));
\r
35 shipRecords.AddRange(GetItemRecords(ship));
\r
37 list.Add(Record.CreateFleetRecord(sniffer.Fleets, fleet.Number));
\r
38 list.AddRange(shipRecords);
\r
40 if (sniffer.AirBase == null)
\r
41 return list.ToArray();
\r
42 foreach (var baseInfo in sniffer.AirBase)
\r
44 list.Add(new Record {Fleet = baseInfo.AreaName + " 基地航空隊"});
\r
46 foreach (var airCorps in baseInfo.AirCorps)
\r
50 list.Add(Record.CreateAirCorpsRecord(airCorps, i++));
\r
51 list.AddRange(airCorps.Planes.Select(Record.CreateCorpsPlaneRecord));
\r
54 return list.ToArray();
\r
57 private static IEnumerable<Record> GetItemRecords(ShipStatus ship)
\r
59 var items = ship.Slot.TakeWhile(item => !item.Empty)
\r
60 .Select((item, i) => Record.CreateItemRecord(item, ship.OnSlot[i], ship.Spec.MaxEq[i]));
\r
61 if (ship.SlotEx.Id <= 0)
\r
63 return items.Concat(new[] {Record.CreateItemRecord(ship.SlotEx, 0, 0)});
\r
68 public string Fleet { get; set; }
\r
69 public string Fleet2 { get; set; }
\r
70 public string Ship { get; set; }
\r
71 public string Ship2 { get; set; }
\r
72 public int Id { get; set; }
\r
73 public string Equip { get; set; }
\r
74 public Color Color { get; set; }
\r
75 public string Spec { get; set; }
\r
76 public string Spec2 { get; set; }
\r
77 public string AircraftSpec { get; set; }
\r
81 Color = Control.DefaultBackColor;
\r
82 Fleet = Ship = Equip = AircraftSpec = "";
\r
85 public static Record CreateShipRecord(ShipStatus ship)
\r
87 return new ShipRecord(ship);
\r
90 private class ShipRecord : Record
\r
92 public ShipRecord(ShipStatus ship)
\r
94 Ship = (ship.Escaped ? "[避]" : "") + ship.Name + " Lv" + ship.Level;
\r
95 Ship2 = $"燃{ship.EffectiveFuelMax} 弾{ship.EffectiveBullMax}";
\r
97 SetAttackPower(ship);
\r
100 private void SetAttackPower(ShipStatus ship)
\r
102 Spec = HideIfZero("砲", ship.EffectiveFirepower) +
\r
103 HideIfZero(" 潜", ship.EffectiveAntiSubmarine) +
\r
104 (ship.CanOpeningAntiSubmarineAttack ? "*" : "");
\r
105 Spec2 = (HideIfZero("雷", ship.EffectiveTorpedo) +
\r
106 HideIfZero(" 夜", ship.NightBattlePower)).TrimStart(' ');
\r
114 public static Record CreateItemRecord(ItemStatus item, int onSlot, int maxEq)
\r
116 return new ItemRecord(item, onSlot, maxEq);
\r
119 private class ItemRecord : Record
\r
121 public ItemRecord(ItemStatus item, int onSlot, int maxEq)
\r
123 Equip = GenEquipString(item);
\r
124 Spec = item.Spec.IsAircraft ? $"+{item.Alv} {onSlot}/{maxEq}" : "";
\r
125 AircraftSpec = GetAircraftSpec(item, onSlot);
\r
126 Color = item.Spec.Color;
\r
129 private static string GetAircraftSpec(ItemStatus item, int onSlot)
\r
131 if (item.Spec.IsDiveBomber) // 爆撃
\r
134 (25 + (int)((item.Spec.Bomber + item.BomberLevelBonus) * Math.Sqrt(onSlot)));
\r
136 if (item.Spec.IsTorpedoBomber)
\r
138 var normal = 25 + item.Spec.Torpedo * Math.Sqrt(onSlot);
\r
139 return "航空戦 " + (int)(normal * 0.8) + "/" + (int)(normal * 1.5);
\r
145 private static string GenEquipString(ItemStatus item)
\r
147 var level = item.Level == 0 ? "" : "★" + item.Level;
\r
148 return StringTruncator.Truncate(item.Spec.Name, level, item.Spec.IsAircraft ? 132 : 180) + level;
\r
151 public static Record CreateFleetRecord(IReadOnlyList<Fleet> fleets, int number)
\r
153 return new FleetRecord(fleets, number);
\r
156 private class FleetRecord : Record
\r
158 public FleetRecord(IReadOnlyList<Fleet> fleets, int number)
\r
160 var fleet = fleets[number];
\r
161 Fleet = new[] {"第一", "第二", "第三", "第四"}[number] + " " + SpeedName(fleet) + " " + SpecTotal(fleet);
\r
162 Fleet2 = Concat(FleetParams(fleet),
\r
163 Concat(GetTp(fleets, number), GetNightContact(fleet), " "), "\r\n");
\r
166 private static string SpeedName(Fleet fleet)
\r
168 var speed = fleet.ActualShips.Min(s => (int?)s.Speed);
\r
169 return new[] {"", "低速", "高速", "高速+", "最速"}[(speed ?? 0) / 5];
\r
172 private static string Concat(string a, string b, string separator)
\r
174 return a == "" ? b : b == "" ? a : a + separator + b;
\r
177 private static string GetTp(IReadOnlyList<Fleet> fleets, int number)
\r
179 var tp = fleets[number].TransportPoint;
\r
180 if (fleets[0].CombinedType != CombinedType.None)
\r
183 tp += fleets[1].TransportPoint;
\r
184 else if (number == 1)
\r
187 return $"TP:S{(int)tp} A{(int)(tp * 0.7)}";
\r
190 private static string GetNightContact(Fleet fleet)
\r
192 return fleet.NightContactTriggerRate > 0 ? $"夜偵:{fleet.NightContactTriggerRate}%" : "";
\r
195 private static string SpecTotal(Fleet fleet)
\r
197 var total = CalcTotal(fleet);
\r
198 return "火" + CutOverFlow(total.FirePower) +
\r
199 " 空" + CutOverFlow(total.AntiAir) +
\r
200 " 潜" + CutOverFlow(total.AntiSubmarine) +
\r
201 " 索" + CutOverFlow(total.LoS);
\r
204 private static string FleetParams(Fleet fleet)
\r
206 var total = CalcTotal(fleet);
\r
207 return "計:" + HideIfZero(" Lv", total.Level) +
\r
208 HideIfZero(" ド", total.Drum) + HideIfZero("(", total.DrumShips, "隻)") +
\r
209 HideIfZero(" 大", fleet.DaihatsuBonus, "%") + "\r\n" +
\r
210 $"戦闘:燃{total.Fuel / 5}弾{total.Bull / 5} 支援:燃{total.Fuel / 2}弾{(int)(total.Bull * 0.8)}";
\r
213 private static Total CalcTotal(Fleet fleet)
\r
215 return fleet.Ships.Aggregate(new Total(), (sum, next) => sum.Add(next));
\r
218 private static int CutOverFlow(int value) => value > 999 ? 999 : value;
\r
220 private class Total
\r
223 public int DrumShips;
\r
225 public int FirePower;
\r
226 public int AntiSubmarine;
\r
227 public int AntiAir;
\r
232 public Total Add(ShipStatus s)
\r
234 var drum = s.Slot.Count(item => item.Spec.IsDrum);
\r
237 DrumShips = DrumShips + (drum != 0 ? 1 : 0),
\r
238 Drum = Drum + drum,
\r
239 Level = Level + s.Level,
\r
240 FirePower = FirePower + s.Firepower,
\r
241 AntiSubmarine = AntiSubmarine + s.MissionAntiSubmarine,
\r
242 AntiAir = AntiAir + s.AntiAir,
\r
244 Fuel = Fuel + s.EffectiveFuelMax,
\r
245 Bull = Bull + s.EffectiveBullMax
\r
251 private static string HideIfZero(string name, double value, string suffix = "")
\r
253 return value > 0 ? name + value.ToString("f1") + suffix : "";
\r
256 private static string HideIfZero(string name, int value, string suffix = "")
\r
258 return value > 0 ? name + value + suffix : "";
\r
261 public static Record CreateAirCorpsRecord(AirBase.AirCorpsInfo airCorps, int number)
\r
263 return new AirCorpsRecord(airCorps, number);
\r
266 private class AirCorpsRecord : Record
\r
268 public AirCorpsRecord(AirBase.AirCorpsInfo airCorps, int number)
\r
270 var corpsFp = airCorps.CalcFighterPower();
\r
273 if (airCorps.Action == 2)
\r
275 spec = "制空:" + RangeString(corpsFp.Interception);
\r
276 spec2 = corpsFp.Difference ? "制空(出撃):" + RangeString(corpsFp.AirCombat) : "";
\r
280 spec = "制空:" + RangeString(corpsFp.AirCombat);
\r
281 spec2 = corpsFp.Difference ? "制空(防空):" + RangeString(corpsFp.Interception) : "";
\r
283 var cost = airCorps.CostForSortie;
\r
284 Ship = new[] {"第一", "第二", "第三"}[number] + " " + airCorps.ActionName;
\r
285 Ship2 = $"出撃コスト:燃{cost[0]}弾{cost[1]}";
\r
286 Spec = spec + $" 距離:{airCorps.Distance}";
\r
291 public static Record CreateCorpsPlaneRecord(AirBase.PlaneInfo plane)
\r
293 return new CorpsPlaneRecord(plane);
\r
296 private class CorpsPlaneRecord : Record
\r
298 public CorpsPlaneRecord(AirBase.PlaneInfo plane)
\r
300 var planeFp = plane.FighterPower;
\r
301 Equip = plane.State != 1 ? plane.StateName : GenEquipString(plane.Slot);
\r
302 Spec = plane.State != 1 ? "" : $"+{plane.Slot.Alv} {plane.Count}/{plane.MaxCount}";
\r
304 $"距離:{plane.Slot.Spec.Distance} 制空:{RangeString(planeFp.AirCombat)}" +
\r
305 (planeFp.Difference ? $" 防空:{RangeString(planeFp.Interception)}" : "");
\r
306 Color = plane.Slot.Spec.Color;
\r
310 private static string RangeString(Range range) => range.Diff ? range.RangeString : range.Min.ToString();
\r