1 // Copyright (C) 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
16 using System.Collections;
\r
17 using System.Collections.Generic;
\r
18 using System.Drawing;
\r
20 using System.Windows.Forms;
\r
22 namespace KancolleSniffer
\r
24 public class FleetPanel : Panel
\r
26 private const int LineHeight = 14;
\r
27 private const int LabelHeight = 12;
\r
28 private Record[] _table;
\r
29 private readonly List<FleetLabels> _labelList = new List<FleetLabels>();
\r
30 private readonly List<Panel> _panelList = new List<Panel>();
\r
31 private readonly ResizableToolTip _toolTip = new ResizableToolTip {ShowAlways = true, AutoPopDelay = 10000};
\r
33 private class Record
\r
35 public string Fleet { get; set; }
\r
36 public string Fleet2 { get; set; }
\r
37 public string Ship { get; set; }
\r
38 public string Ship2 { get; set; }
\r
39 public int Id { get; set; }
\r
40 public string Equip { get; set; }
\r
41 public Color Color { get; set; }
\r
42 public string Spec { get; set; }
\r
43 public string Spec2 { get; set; }
\r
44 public string AircraftSpec { get; set; }
\r
48 Fleet = Ship = Equip = AircraftSpec = "";
\r
49 Color = DefaultBackColor;
\r
53 public void Update(Sniffer sniffer)
\r
55 CreateTable(sniffer);
\r
62 private void CreateTable(Sniffer sniffer)
\r
64 var list = new List<Record>();
\r
65 var fn = new[] {"第一", "第二", "第三", "第四"};
\r
66 for (var f = 0; f < fn.Length; f++)
\r
73 var antiAirTotal = 0;
\r
77 var ships = new List<Record>();
\r
78 foreach (var s in sniffer.GetShipStatuses(f))
\r
81 var equips = new List<Record>();
\r
82 for (var i = 0; i < s.Slot.Length; i++)
\r
84 var item = s.Slot[i];
\r
85 var onslot = s.OnSlot[i];
\r
86 var max = s.Spec.MaxEq[i];
\r
89 if (item.Spec.Name == "ドラム缶(輸送用)")
\r
92 if (item.Spec.IsDiveBomber) // 爆撃
\r
95 (25 + (int)((item.Spec.Bomber + item.BomberLevelBonus) * Math.Sqrt(onslot)));
\r
97 else if (item.Spec.IsTorpedoBomber)
\r
99 var normal = 25 + item.Spec.Torpedo * Math.Sqrt(onslot);
\r
100 airspec = "航空戦 " + (int)(normal * 0.8) + "/" + (int)(normal * 1.5);
\r
103 equips.Add(new Record
\r
105 Equip = GenEquipString(item),
\r
106 Spec = item.Spec.IsAircraft ? $"+{item.Alv} {onslot}/{max}" : "",
\r
107 AircraftSpec = airspec,
\r
108 Color = item.Spec.Color
\r
111 if (s.SlotEx.Id > 0)
\r
113 var item = s.SlotEx;
\r
114 equips.Add(new Record {Equip = GenEquipString(item), Color = item.Spec.Color});
\r
119 levelTotal += s.Level;
\r
120 fpTotal += s.Firepower;
\r
121 aswTotal += s.MissionAntiSubmarine;
\r
122 antiAirTotal += s.AntiAir;
\r
124 fuelTotal += Math.Max((int)(s.Spec.FuelMax * (s.Level >= 100 ? 0.85 : 1.0)), 1);
\r
125 bullTotal += Math.Max((int)(s.Spec.BullMax * (s.Level >= 100 ? 0.85 : 1.0)), 1);
\r
126 var fire = s.EffectiveFirepower;
\r
127 var subm = s.EffectiveAntiSubmarine;
\r
128 var torp = s.EffectiveTorpedo;
\r
129 var night = s.NightBattlePower;
\r
130 var oasa = s.CanOpeningAntiSubmarineAttack ? "*" : "";
\r
131 var ship = new Record
\r
133 Ship = (s.Escaped ? "[避]" : "") + s.Name + " Lv" + s.Level,
\r
136 // ReSharper disable CompareOfFloatsByEqualityOperator
\r
137 Spec = (fire == 0 ? "" : $"砲{fire:f1}") + (subm == 0 ? "" : $" 潜{subm:f1}{oasa}"),
\r
138 Spec2 = (torp == 0 ? "" : $"雷{torp:f1}") + (night == 0 ? "" : $" 夜{night:f1}")
\r
139 // ReSharper restore CompareOfFloatsByEqualityOperator
\r
141 if (ship.Spec == "")
\r
143 ship.Spec = ship.Spec2;
\r
147 ships.AddRange(equips);
\r
149 var daihatsu = sniffer.GetDaihatsuBonus(f);
\r
150 var tp = sniffer.GetTransportPoint(f);
\r
151 if (sniffer.CombinedFleetType != 0 && f == 0)
\r
152 tp += sniffer.GetTransportPoint(1);
\r
153 list.Add(new Record
\r
155 Fleet = fn[f] + (levelTotal == 0 ? "" : " Lv" + levelTotal) +
\r
156 (drumTotal == 0 ? "" : " ドラム缶" + drumTotal + "(" + drumShips + "隻)") +
\r
157 (daihatsu > 0 ? $" 大発{daihatsu * 100:f1}%" : ""),
\r
159 "火" + CutOverFlow(fpTotal) +
\r
160 " 空" + CutOverFlow(antiAirTotal) +
\r
161 " 潜" + CutOverFlow(aswTotal) +
\r
162 " 索" + CutOverFlow(losTotal) + "\r\n" +
\r
163 $"戦闘:燃{fuelTotal / 5}弾{bullTotal / 5} 支援:燃{fuelTotal / 2}弾{(int)(bullTotal * 0.8)}" +
\r
164 (sniffer.CombinedFleetType != 0 && f == 1 ? "" : $"\r\nTP:S{(int)tp} A{(int)(tp * 0.7)}")
\r
166 list.AddRange(ships);
\r
168 if (sniffer.BaseAirCorps != null)
\r
170 var name = new[] {"第一", "第二", "第三"};
\r
171 foreach (var baseInfo in sniffer.BaseAirCorps)
\r
173 list.Add(new Record {Fleet = baseInfo.AreaName + " 基地航空隊"});
\r
175 foreach (var airCorps in baseInfo.AirCorps)
\r
177 if (i >= name.Length)
\r
179 var corpsFp = airCorps.FighterPower;
\r
182 if (airCorps.Action == 2)
\r
184 spec = "制空:" + RangeString(corpsFp.Interception);
\r
185 spec2 = corpsFp.IsInterceptor ? "制空(出撃):" + RangeString(corpsFp.AirCombat) : "";
\r
189 spec = "制空:" + RangeString(corpsFp.AirCombat);
\r
190 spec2 = corpsFp.IsInterceptor ? "制空(防空):" + RangeString(corpsFp.Interception) : "";
\r
192 var cost = airCorps.CostForSortie;
\r
193 list.Add(new Record
\r
195 Ship = name[i++] + " " + airCorps.ActionName,
\r
196 Ship2 = $"出撃コスト:燃{cost[0]}弾{cost[1]}",
\r
197 Spec = spec + " 距離:" + airCorps.Distance,
\r
200 list.AddRange(airCorps.Planes.Select(plane =>
\r
202 var planeFp = plane.FighterPower;
\r
205 Equip = plane.State != 1 ? plane.StateName : GenEquipString(plane.Slot),
\r
206 Spec = plane.State != 1 ? "" : $"+{plane.Slot.Alv} {plane.Count}/{plane.MaxCount}",
\r
208 $"距離:{plane.Slot.Spec.Distance} 制空:{RangeString(planeFp.AirCombat)}" +
\r
209 (planeFp.IsInterceptor ? $" 防空:{RangeString(planeFp.Interception)}" : ""),
\r
210 Color = plane.Slot.Spec.Color
\r
216 _table = list.ToArray();
\r
219 private string RangeString(int[] fp) => fp[0] == fp[1] ? fp[0].ToString() : $"{fp[0]}~{fp[1]}";
\r
221 private int CutOverFlow(int value) => value > 999 ? 999 : value;
\r
223 private string GenEquipString(ItemStatus item)
\r
225 var name = item.Spec.Name;
\r
226 var attr = item.Level == 0 ? "" : "★" + item.Level;
\r
227 var proposed = new Size(int.MaxValue, int.MaxValue);
\r
228 var maxWidth = item.Spec.IsAircraft ? 132 : 180;
\r
229 var result = name + attr;
\r
230 if (TextRenderer.MeasureText(result, Font, proposed).Width <= maxWidth)
\r
232 var truncated = "";
\r
233 foreach (var ch in name)
\r
235 var tmp = truncated + ch;
\r
236 if (TextRenderer.MeasureText(tmp + attr, Font, proposed).Width > maxWidth)
\r
240 return truncated + attr;
\r
243 private void CreateLabels()
\r
245 for (var i = _labelList.Count; i < _table.Length; i++)
\r
249 private class FleetLabels : IEnumerable<ShipLabel>
\r
251 public ShipLabel Fleet { get; set; }
\r
252 public ShipLabel Name { get; set; }
\r
253 public ShipLabel Equip { get; set; }
\r
254 public ShipLabel EquipColor { get; set; }
\r
255 public ShipLabel Spec { get; set; }
\r
257 public IEnumerator<ShipLabel> GetEnumerator() =>
\r
258 ((IEnumerable<ShipLabel>)new[] {Fleet, Name, Equip, EquipColor, Spec}).GetEnumerator();
\r
260 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
\r
263 private void CreateLabels(int i)
\r
265 var y = 1 + LineHeight * i;
\r
266 var lbp = new Panel
\r
268 Location = new Point(0, y),
\r
269 Size = new Size(ListForm.PanelWidth, LineHeight),
\r
270 BackColor = ShipLabel.ColumnColors[(i + 1) % 2],
\r
273 lbp.Scale(ShipLabel.ScaleFactor);
\r
274 lbp.Tag = lbp.Location.Y;
\r
275 var labels = new FleetLabels
\r
277 Fleet = new ShipLabel {Location = new Point(1, 2), AutoSize = true},
\r
278 Name = new ShipLabel {Location = new Point(10, 2), AutoSize = true},
\r
279 Equip = new ShipLabel {Location = new Point(38, 2), AutoSize = true},
\r
280 EquipColor = new ShipLabel {Location = new Point(35, 2), Size = new Size(4, LabelHeight - 2)},
\r
281 Spec = new ShipLabel {Location = new Point(217, 2), AutoSize = true, AnchorRight = true}
\r
283 _labelList.Add(labels);
\r
284 _panelList.Add(lbp);
\r
285 lbp.Controls.AddRange(labels.Cast<Control>().ToArray());
\r
287 foreach (var label in labels)
\r
290 label.PresetColor =
\r
291 label.BackColor = ShipLabel.ColumnColors[(i + 1) % 2];
\r
295 private void SetRecords()
\r
297 for (var i = 0; i < _table.Length; i++)
\r
299 for (var i = _table.Length; i < _labelList.Count; i++)
\r
300 _panelList[i].Visible = false;
\r
303 private void SetRecord(int i)
\r
305 var lbp = _panelList[i];
\r
307 lbp.Location = new Point(lbp.Left, (int)lbp.Tag + AutoScrollPosition.Y);
\r
309 var labels = _labelList[i];
\r
310 labels.Fleet.Text = e.Fleet;
\r
311 labels.Name.SetName(e.Ship);
\r
313 _toolTip.SetToolTip(labels.Name, e.Ship2);
\r
314 labels.Equip.Text = e.Equip;
\r
315 labels.EquipColor.Visible = e.Equip != "";
\r
316 labels.EquipColor.BackColor = e.Color;
\r
317 labels.Spec.Text = e.Spec;
\r
318 if (e.Fleet != "" && e.Fleet2 != "")
\r
319 _toolTip.SetToolTip(labels.Fleet, e.Fleet2);
\r
320 _toolTip.SetToolTip(labels.Equip, e.AircraftSpec != "" ? e.AircraftSpec : "");
\r
321 _toolTip.SetToolTip(labels.Spec, e.Spec2 != "" ? e.Spec2 : "");
\r
322 lbp.Visible = true;
\r
325 public void ShowShip(int id)
\r
327 var i = Array.FindIndex(_table, e => e.Id == id);
\r
330 var y = (int)Math.Round(ShipLabel.ScaleFactor.Height * LineHeight * i);
\r
331 AutoScrollPosition = new Point(0, y);
\r
334 public void ShowFleet(string fn)
\r
336 var i = Array.FindIndex(_table, e => e.Fleet.StartsWith(fn));
\r
339 var y = (int)Math.Round(ShipLabel.ScaleFactor.Height * LineHeight * i);
\r
340 AutoScrollPosition = new Point(0, y);
\r
343 protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
\r
345 base.ScaleControl(factor, specified);
\r
346 if (factor.Height > 1)
\r
347 _toolTip.Font = new Font(_toolTip.Font.FontFamily, _toolTip.Font.Size * factor.Height);
\r