OSDN Git Service

PresetColorを廃止する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / FleetPanel.cs
1 // Copyright (C) 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\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
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\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
14 \r
15 using System;\r
16 using System.Collections;\r
17 using System.Collections.Generic;\r
18 using System.Drawing;\r
19 using System.Linq;\r
20 using System.Windows.Forms;\r
21 using KancolleSniffer.Model;\r
22 \r
23 namespace KancolleSniffer.View\r
24 {\r
25     public class FleetPanel : PanelWithToolTip\r
26     {\r
27         private const int LineHeight = 14;\r
28         private const int LabelHeight = 12;\r
29         private Record[] _table = new Record[0];\r
30         private readonly List<FleetLabels> _labelList = new List<FleetLabels>();\r
31         private readonly List<Panel> _panelList = new List<Panel>();\r
32 \r
33         public FleetPanel()\r
34         {\r
35             ToolTip.AutoPopDelay = 10000;\r
36         }\r
37 \r
38         public class Record\r
39         {\r
40             public string Fleet { get; set; }\r
41             public string Fleet2 { get; set; }\r
42             public string Ship { get; set; }\r
43             public string Ship2 { get; set; }\r
44             public int Id { get; set; }\r
45             public string Equip { get; set; }\r
46             public Color Color { get; set; }\r
47             public string Spec { get; set; }\r
48             public string Spec2 { get; set; }\r
49             public string AircraftSpec { get; set; }\r
50 \r
51             public Record()\r
52             {\r
53                 Fleet = Ship = Equip = AircraftSpec = "";\r
54                 Color = DefaultBackColor;\r
55             }\r
56         }\r
57 \r
58         public void Update(Sniffer sniffer)\r
59         {\r
60             _table = CreateTable(sniffer);\r
61             SuspendLayout();\r
62             CreateLabels();\r
63             SetRecords();\r
64             ResumeLayout();\r
65         }\r
66 \r
67         private class Total\r
68         {\r
69             public int Drum;\r
70             public int DrumShips;\r
71             public int Level;\r
72             public int FirePower;\r
73             public int AntiSubmarine;\r
74             public int AntiAir;\r
75             public int LoS;\r
76             public int Fuel;\r
77             public int Bull;\r
78 \r
79             public void Add(ShipStatus s)\r
80             {\r
81                 var drum = s.Slot.Count(item => item.Spec.IsDrum);\r
82                 DrumShips += drum != 0 ? 1 : 0;\r
83                 Drum += drum;\r
84                 Level += s.Level;\r
85                 FirePower += s.Firepower;\r
86                 AntiSubmarine += s.MissionAntiSubmarine;\r
87                 AntiAir += s.AntiAir;\r
88                 LoS += s.LoS;\r
89                 Fuel += s.EffectiveFuelMax;\r
90                 Bull += s.EffectiveBullMax;\r
91             }\r
92         }\r
93 \r
94         public Record[] CreateTable(Sniffer sniffer)\r
95         {\r
96             var list = new List<Record>();\r
97             var fn = new[] {"第一", "第二", "第三", "第四"};\r
98             foreach (var fleet in sniffer.Fleets)\r
99             {\r
100                 var total = new Total();\r
101                 var shipRecords = new List<Record>();\r
102                 var speed = int.MaxValue;\r
103                 foreach (var ship in fleet.ActualShips)\r
104                 {\r
105                     var equips = new List<Record>();\r
106                     for (var i = 0; i < ship.Slot.Count; i++)\r
107                     {\r
108                         var item = ship.Slot[i];\r
109                         var onSlot = ship.OnSlot[i];\r
110                         var max = ship.Spec.MaxEq[i];\r
111                         if (item.Empty)\r
112                             continue;\r
113                         var airSpec = "";\r
114                         if (item.Spec.IsDiveBomber) // 爆撃\r
115                         {\r
116                             airSpec = "航空戦 " +\r
117                                       (25 + (int)((item.Spec.Bomber + item.BomberLevelBonus) * Math.Sqrt(onSlot)));\r
118                         }\r
119                         else if (item.Spec.IsTorpedoBomber)\r
120                         {\r
121                             var normal = 25 + item.Spec.Torpedo * Math.Sqrt(onSlot);\r
122                             airSpec = "航空戦 " + (int)(normal * 0.8) + "/" + (int)(normal * 1.5);\r
123                         }\r
124                         equips.Add(new Record\r
125                         {\r
126                             Equip = GenEquipString(item),\r
127                             Spec = item.Spec.IsAircraft ? $"+{item.Alv} {onSlot}/{max}" : "",\r
128                             AircraftSpec = airSpec,\r
129                             Color = item.Spec.Color\r
130                         });\r
131                     }\r
132                     if (ship.SlotEx.Id > 0)\r
133                     {\r
134                         var item = ship.SlotEx;\r
135                         equips.Add(new Record {Equip = GenEquipString(item), Color = item.Spec.Color});\r
136                     }\r
137                     total.Add(ship);\r
138                     speed = Math.Min(speed, ship.Speed);\r
139                     var fire = ship.EffectiveFirepower;\r
140                     // ReSharper disable IdentifierTypo\r
141                     var subm = ship.EffectiveAntiSubmarine;\r
142                     var torp = ship.EffectiveTorpedo;\r
143                     var night = ship.NightBattlePower;\r
144                     var oasa = ship.CanOpeningAntiSubmarineAttack ? "*" : "";\r
145                     // ReSharper restore IdentifierTypo\r
146                     var record = new Record\r
147                     {\r
148                         Ship = (ship.Escaped ? "[避]" : "") + ship.Name + " Lv" + ship.Level,\r
149                         Ship2 = $"燃{ship.EffectiveFuelMax} 弾{ship.EffectiveBullMax}",\r
150                         Id = ship.Id,\r
151                         Spec = HideIfZero("砲", fire) + HideIfZero(" 潜", subm) + oasa,\r
152                         Spec2 = (HideIfZero("雷", torp) + HideIfZero(" 夜", night)).TrimStart(' ')\r
153                     };\r
154                     if (record.Spec == "")\r
155                     {\r
156                         record.Spec = record.Spec2;\r
157                         record.Spec2 = "";\r
158                     }\r
159                     shipRecords.Add(record);\r
160                     shipRecords.AddRange(equips);\r
161                 }\r
162                 var daihatsu = fleet.DaihatsuBonus;\r
163                 var tp = fleet.TransportPoint;\r
164                 if (sniffer.IsCombinedFleet && fleet.Number == 0)\r
165                     tp += sniffer.Fleets[1].TransportPoint;\r
166                 var speedName = speed == int.MaxValue ? "" : new[] {"", "低速", "高速", "高速+", "最速"}[speed / 5];\r
167                 list.Add(new Record\r
168                 {\r
169                     Fleet = fn[fleet.Number] + " " + speedName,\r
170                     Fleet2 =\r
171                         "計:" + HideIfZero(" Lv", total.Level) +\r
172                         HideIfZero(" ド", total.Drum) + HideIfZero("(", total.DrumShips, "隻)") +\r
173                         HideIfZero(" 大", daihatsu * 100, "%") + "\r\n" +\r
174                         "  火" + CutOverFlow(total.FirePower) +\r
175                         " 空" + CutOverFlow(total.AntiAir) +\r
176                         " 潜" + CutOverFlow(total.AntiSubmarine) +\r
177                         " 索" + CutOverFlow(total.LoS) + "\r\n" +\r
178                         $"戦闘:燃{total.Fuel / 5}弾{total.Bull / 5} 支援:燃{total.Fuel / 2}弾{(int)(total.Bull * 0.8)}" +\r
179                         (sniffer.IsCombinedFleet && fleet.Number == 1\r
180                             ? ""\r
181                             : $"\r\nTP:S{(int)tp} A{(int)(tp * 0.7)}")\r
182                 });\r
183                 list.AddRange(shipRecords);\r
184             }\r
185             if (sniffer.AirBase != null)\r
186             {\r
187                 var name = new[] {"第一", "第二", "第三"};\r
188                 foreach (var baseInfo in sniffer.AirBase)\r
189                 {\r
190                     list.Add(new Record {Fleet = baseInfo.AreaName + " 基地航空隊"});\r
191                     var i = 0;\r
192                     foreach (var airCorps in baseInfo.AirCorps)\r
193                     {\r
194                         if (i >= name.Length)\r
195                             break;\r
196                         var corpsFp = airCorps.CalcFighterPower();\r
197                         var airCombat = new[] { (int)corpsFp[0].AirCombat, (int)corpsFp[1].AirCombat };\r
198                         var interception = new[] { (int)corpsFp[0].Interception, (int)corpsFp[1].Interception };\r
199                         var different = interception[0] != airCombat[0];\r
200                         string spec;\r
201                         string spec2;\r
202                         if (airCorps.Action == 2)\r
203                         {\r
204                             spec = "制空:" + RangeString(interception);\r
205                             spec2 = different ? "制空(出撃):" + RangeString(airCombat) : "";\r
206                         }\r
207                         else\r
208                         {\r
209                             spec = "制空:" + RangeString(airCombat);\r
210                             spec2 = different ? "制空(防空):" + RangeString(interception) : "";\r
211                         }\r
212                         var cost = airCorps.CostForSortie;\r
213                         list.Add(new Record\r
214                         {\r
215                             Ship = name[i++] + " " + airCorps.ActionName,\r
216                             Ship2 = $"出撃コスト:燃{cost[0]}弾{cost[1]}",\r
217                             Spec = spec + $" 距離:{airCorps.Distance}",\r
218                             Spec2 = spec2\r
219                         });\r
220                         list.AddRange(airCorps.Planes.Select(plane =>\r
221                         {\r
222                             var planeFp = plane.FighterPower;\r
223                             airCombat = new[] {(int)planeFp[0].AirCombat, (int)planeFp[1].AirCombat};\r
224                             interception = new[] {(int) planeFp[0].Interception, (int)planeFp[1].Interception };\r
225                             different = interception[0] != airCombat[0];\r
226                             return new Record\r
227                             {\r
228                                 Equip = plane.State != 1 ? plane.StateName : GenEquipString(plane.Slot),\r
229                                 Spec = plane.State != 1 ? "" : $"+{plane.Slot.Alv} {plane.Count}/{plane.MaxCount}",\r
230                                 AircraftSpec =\r
231                                     $"距離:{plane.Slot.Spec.Distance} 制空:{RangeString(airCombat)}" +\r
232                                     (different ? $" 防空:{RangeString(interception)}" : ""),\r
233                                 Color = plane.Slot.Spec.Color\r
234                             };\r
235                         }));\r
236                     }\r
237                 }\r
238             }\r
239             return list.ToArray();\r
240         }\r
241 \r
242         private string RangeString(int[] fp) => fp[0] == fp[1] ? fp[0].ToString() : $"{fp[0]}~{fp[1]}";\r
243 \r
244         private int CutOverFlow(int value) => value > 999 ? 999 : value;\r
245 \r
246         private string HideIfZero(string name, double value, string suffix = "")\r
247         {\r
248             return value > 0 ? name + value.ToString("f1") + suffix : "";\r
249         }\r
250 \r
251         private string HideIfZero(string name, int value, string suffix = "")\r
252         {\r
253             return value > 0 ? name + value + suffix : "";\r
254         }\r
255 \r
256         private string GenEquipString(ItemStatus item)\r
257         {\r
258             var name = item.Spec.Name;\r
259             var attr = item.Level == 0 ? "" : "★" + item.Level;\r
260             var proposed = new Size(int.MaxValue, int.MaxValue);\r
261             var maxWidth = item.Spec.IsAircraft ? 132 : 180;\r
262             var result = name + attr;\r
263             if (TextRenderer.MeasureText(result, Font, proposed).Width <= maxWidth)\r
264                 return result;\r
265             var truncated = "";\r
266             foreach (var ch in name)\r
267             {\r
268                 var tmp = truncated + ch;\r
269                 if (TextRenderer.MeasureText(tmp + attr, Font, proposed).Width > maxWidth)\r
270                     break;\r
271                 truncated = tmp;\r
272             }\r
273             return truncated + attr;\r
274         }\r
275 \r
276         private void CreateLabels()\r
277         {\r
278             for (var i = _labelList.Count; i < _table.Length; i++)\r
279                 CreateLabels(i);\r
280         }\r
281 \r
282         private class FleetLabels : IEnumerable<ShipLabel>\r
283         {\r
284             public ShipLabel Fleet { get; set; }\r
285             public ShipLabel Name { get; set; }\r
286             public ShipLabel Equip { get; set; }\r
287             public ShipLabel EquipColor { get; set; }\r
288             public ShipLabel Spec { get; set; }\r
289 \r
290             public IEnumerator<ShipLabel> GetEnumerator() =>\r
291                 ((IEnumerable<ShipLabel>)new[] {Fleet, Name, Equip, EquipColor, Spec}).GetEnumerator();\r
292 \r
293             IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\r
294         }\r
295 \r
296         private void CreateLabels(int i)\r
297         {\r
298             var y = 1 + LineHeight * i;\r
299             var lbp = new Panel\r
300             {\r
301                 Location = new Point(0, y),\r
302                 Size = new Size(ListForm.PanelWidth, LineHeight),\r
303                 BackColor = ShipLabel.ColumnColors[(i + 1) % 2],\r
304                 Visible = false\r
305             };\r
306             Scaler.Scale(lbp);\r
307             lbp.Tag = lbp.Location.Y;\r
308             var labels = new FleetLabels\r
309             {\r
310                 Fleet = new ShipLabel {Location = new Point(1, 2), AutoSize = true},\r
311                 Name = new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
312                 Equip = new ShipLabel {Location = new Point(38, 2), AutoSize = true},\r
313                 EquipColor = new ShipLabel {Location = new Point(35, 2), Size = new Size(4, LabelHeight - 2)},\r
314                 Spec = new ShipLabel {Location = new Point(217, 2), AutoSize = true, AnchorRight = true}\r
315             };\r
316             _labelList.Add(labels);\r
317             _panelList.Add(lbp);\r
318             lbp.Controls.AddRange(labels.Cast<Control>().ToArray());\r
319             Controls.Add(lbp);\r
320             foreach (var label in labels)\r
321             {\r
322                 Scaler.Scale(label);\r
323                 label.BackColor = ShipLabel.ColumnColors[(i + 1) % 2];\r
324             }\r
325         }\r
326 \r
327         private void SetRecords()\r
328         {\r
329             for (var i = 0; i < _table.Length; i++)\r
330                 SetRecord(i);\r
331             for (var i = _table.Length; i < _labelList.Count; i++)\r
332                 _panelList[i].Visible = false;\r
333         }\r
334 \r
335         private void SetRecord(int i)\r
336         {\r
337             var lbp = _panelList[i];\r
338             if (!lbp.Visible)\r
339                 lbp.Location = new Point(lbp.Left, (int)lbp.Tag + AutoScrollPosition.Y);\r
340             var e = _table[i];\r
341             var labels = _labelList[i];\r
342             labels.Fleet.Text = e.Fleet;\r
343             labels.Name.SetName(e.Ship);\r
344             if (e.Ship2 != "")\r
345                 ToolTip.SetToolTip(labels.Name, e.Ship2);\r
346             labels.Equip.Text = e.Equip;\r
347             labels.EquipColor.Visible = e.Equip != "";\r
348             labels.EquipColor.BackColor = e.Color;\r
349             labels.Spec.Text = e.Spec;\r
350             if (e.Fleet != "" && e.Fleet2 != "")\r
351                 ToolTip.SetToolTip(labels.Fleet, e.Fleet2);\r
352             ToolTip.SetToolTip(labels.Equip, e.AircraftSpec != "" ? e.AircraftSpec : "");\r
353             ToolTip.SetToolTip(labels.Spec, e.Spec2 != "" ? e.Spec2 : "");\r
354             lbp.Visible = true;\r
355         }\r
356 \r
357         public void ShowShip(int id)\r
358         {\r
359             var i = Array.FindIndex(_table, e => e.Id == id);\r
360             if (i == -1)\r
361                 return;\r
362             var y = Scaler.ScaleHeight(LineHeight * i);\r
363             AutoScrollPosition = new Point(0, y);\r
364         }\r
365 \r
366         public void ShowFleet(string fn)\r
367         {\r
368             var i = Array.FindIndex(_table, e => e.Fleet.StartsWith(fn));\r
369             if (i == -1)\r
370                 return;\r
371             var y = Scaler.ScaleHeight(LineHeight * i);\r
372             AutoScrollPosition = new Point(0, y);\r
373         }\r
374     }\r
375 }