OSDN Git Service

PresetColorを廃止する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / BattleResultPanel.cs
1 // Copyright (C) 2017 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.Generic;\r
17 using System.Drawing;\r
18 using System.Linq;\r
19 using System.Text.RegularExpressions;\r
20 using System.Windows.Forms;\r
21 using KancolleSniffer.Model;\r
22 using static System.Math;\r
23 \r
24 namespace KancolleSniffer.View\r
25 {\r
26     public class BattleResultPanel : PanelWithToolTip\r
27     {\r
28         private const int LineHeight = 16;\r
29         private readonly List<ShipLabel[]> _friendLabels = new List<ShipLabel[]>();\r
30         private readonly List<ShipLabel[]> _enemyLabels = new List<ShipLabel[]>();\r
31         private readonly List<Panel> _panelList = new List<Panel>();\r
32         private readonly List<ShipLabel> _hpLabels = new List<ShipLabel>();\r
33         private readonly BattleInfo.BattleResult[] _result = new BattleInfo.BattleResult[2];\r
34         private Label _phaseLabel, _rankLabel, _supportLabel, _cellLabel;\r
35         private readonly BattleResultRank[] _rank = new BattleResultRank[2];\r
36         private readonly InformationPanel _informationPanel;\r
37         private CellInfo _cellInfo;\r
38         private string _supportType;\r
39 \r
40         public Spoiler Spoilers { get; set; }\r
41 \r
42         public BattleResultPanel()\r
43         {\r
44             SuspendLayout();\r
45             CreateLabels();\r
46             _informationPanel = new InformationPanel();\r
47             Controls.Add(_informationPanel);\r
48             ResumeLayout();\r
49         }\r
50 \r
51         public event Action HpLabelClick;\r
52 \r
53         private void HpLabelClickHandler(object sender, EventArgs ev)\r
54         {\r
55             HpLabelClick?.Invoke();\r
56         }\r
57 \r
58         public void ToggleHpPercent()\r
59         {\r
60             foreach (var label in _hpLabels)\r
61                 label.ToggleHpPercent();\r
62         }\r
63 \r
64         public void Update(Sniffer sniffer)\r
65         {\r
66             var state = sniffer.Battle.BattleState;\r
67             _cellInfo = sniffer.CellInfo;\r
68             switch (sniffer.Battle.BattleState)\r
69             {\r
70                 case BattleState.None:\r
71                     if (_result[0] == null && _result[1] == null)\r
72                         return;\r
73                     ClearResult();\r
74                     SetPhase("結果");\r
75                     UpdateCellInfo(_cellInfo);\r
76                     return;\r
77                 case BattleState.Day:\r
78                 case BattleState.SpNight:\r
79                     _result[0] = _result[1] = null;\r
80                     break;\r
81                 case BattleState.Result:\r
82                 case BattleState.Unknown:\r
83                     return;\r
84             }\r
85             _supportType = sniffer.Battle.SupportType;\r
86             if ((Spoilers & Spoiler.BattleResult) != 0)\r
87             {\r
88                 ShowResult(sniffer.Battle.Result);\r
89                 ShowResultRank(sniffer.Battle.ResultRank);\r
90                 switch (state)\r
91                 {\r
92                     case BattleState.Day:\r
93                         _result[0] = sniffer.Battle.Result;\r
94                         _rank[0] = sniffer.Battle.ResultRank;\r
95                         SetPhase("昼戦");\r
96                         break;\r
97                     case BattleState.Night:\r
98                     case BattleState.SpNight:\r
99                         _result[1] = sniffer.Battle.Result;\r
100                         _rank[1] = sniffer.Battle.ResultRank;\r
101                         SetPhase("夜戦");\r
102                         break;\r
103                 }\r
104                 _informationPanel.Visible = true;\r
105             }\r
106             else\r
107             {\r
108                 ClearResult();\r
109                 SetPhase("結果");\r
110                 switch (state)\r
111                 {\r
112                     case BattleState.Day:\r
113                         _result[0] = sniffer.Battle.Result;\r
114                         _rank[0] = sniffer.Battle.ResultRank;\r
115                         break;\r
116                     case BattleState.Night:\r
117                     case BattleState.SpNight:\r
118                         _result[1] = sniffer.Battle.Result;\r
119                         _rank[1] = sniffer.Battle.ResultRank;\r
120                         break;\r
121                 }\r
122             }\r
123             _informationPanel.SetInformation(sniffer.Battle);\r
124         }\r
125 \r
126         private void PhaseLabelClick(object sender, EventArgs ev)\r
127         {\r
128             switch (_phaseLabel.Text)\r
129             {\r
130                 case "結果":\r
131                     if (_result[0] != null)\r
132                     {\r
133                         ShowResult(_result[0]);\r
134                         ShowResultRank(_rank[0]);\r
135                         SetPhase("昼戦");\r
136                     }\r
137                     else if (_result[1] != null)\r
138                     {\r
139                         ShowResult(_result[1]);\r
140                         ShowResultRank(_rank[1]);\r
141                         SetPhase("夜戦");\r
142                     }\r
143                     break;\r
144                 case "昼戦":\r
145                     if (_result[1] != null)\r
146                     {\r
147                         ShowResult(_result[1]);\r
148                         ShowResultRank(_rank[1]);\r
149                         SetPhase("夜戦");\r
150                     }\r
151                     break;\r
152                 case "夜戦":\r
153                     if (_result[0] != null)\r
154                     {\r
155                         ShowResult(_result[0]);\r
156                         ShowResultRank(_rank[0]);\r
157                         SetPhase("昼戦");\r
158                     }\r
159                     break;\r
160             }\r
161         }\r
162 \r
163         private void SetPhase(string phase)\r
164         {\r
165             _phaseLabel.Text = phase;\r
166             if (phase == "結果" || _result[0] != null && _result[1] != null)\r
167             {\r
168                 _phaseLabel.BorderStyle = BorderStyle.FixedSingle;\r
169                 _phaseLabel.Cursor = Cursors.Hand;\r
170             }\r
171             else\r
172             {\r
173                 _phaseLabel.BorderStyle = BorderStyle.None;\r
174                 _phaseLabel.Cursor = Cursors.Default;\r
175             }\r
176         }\r
177 \r
178         private Point _scrollPosition;\r
179 \r
180         private void ClearResult()\r
181         {\r
182             _scrollPosition = AutoScrollPosition;\r
183             foreach (var panel in _panelList)\r
184                 panel.Visible = false;\r
185             _informationPanel.Visible = false;\r
186             _rankLabel.Text = "";\r
187             _supportLabel.Text = "";\r
188         }\r
189 \r
190         private void ShowResult(BattleInfo.BattleResult result)\r
191         {\r
192             SuspendLayout();\r
193             AutoScrollPosition = _scrollPosition;\r
194             var friend = result.Friend;\r
195             var enemy = result.Enemy;\r
196             for (var i = 0; i < friend.Main.Length; i++)\r
197             {\r
198                 var labels = _friendLabels[i];\r
199                 var ship = friend.Main[i];\r
200                 labels[0].SetHp(ship);\r
201                 labels[1].SetName(ship, ShipNameWidth.BattleResult);\r
202                 ToolTip.SetToolTip(labels[1], GetEquipString(ship));\r
203             }\r
204             if (friend.Guard.Length > 0)\r
205             {\r
206                 _friendLabels[friend.Main.Length][1].Text = "護衛";\r
207                 _friendLabels[friend.Main.Length][0].SetHp(null);\r
208                 for (var i = 0; i < friend.Guard.Length; i++)\r
209                 {\r
210                     var labels = _friendLabels[friend.Main.Length + 1 + i];\r
211                     var ship = friend.Guard[i];\r
212                     labels[0].SetHp(ship);\r
213                     labels[1].SetName(ship, ShipNameWidth.BattleResult);\r
214                     ToolTip.SetToolTip(labels[1], GetEquipString(ship));\r
215                 }\r
216             }\r
217             var friendLines = friend.Main.Length + (friend.Guard.Length > 0 ? friend.Guard.Length + 1 : 0);\r
218             for (var i = friendLines; i < _friendLabels.Count; i++)\r
219             {\r
220                 _friendLabels[i][0].SetHp(null);\r
221                 _friendLabels[i][1].SetName("");\r
222             }\r
223             for (var i = 0; i < enemy.Main.Length; i++)\r
224             {\r
225                 var labels = _enemyLabels[i];\r
226                 var ship = enemy.Main[i];\r
227                 labels[0].SetHp(ship);\r
228                 labels[1].SetName(ShortenName(ship.Name));\r
229                 ToolTip.SetToolTip(labels[1], GetEquipString(ship));\r
230             }\r
231             if (enemy.Guard.Length > 0)\r
232             {\r
233                 _enemyLabels[enemy.Main.Length][1].Text = "護衛";\r
234                 _enemyLabels[enemy.Main.Length][0].SetHp(null);\r
235                 for (var i = 0; i < enemy.Guard.Length; i++)\r
236                 {\r
237                     var labels = _enemyLabels[enemy.Main.Length + 1 + i];\r
238                     var ship = enemy.Guard[i];\r
239                     labels[0].SetHp(ship);\r
240                     labels[1].SetName(ShortenName(ship.Name));\r
241                     ToolTip.SetToolTip(labels[1], GetEquipString(ship));\r
242                 }\r
243             }\r
244             var enemyLines = enemy.Main.Length + (enemy.Guard.Length > 0 ? enemy.Guard.Length + 1 : 0);\r
245             for (var i = enemyLines; i < _enemyLabels.Count; i++)\r
246             {\r
247                 _enemyLabels[i][0].SetHp(null);\r
248                 _enemyLabels[i][1].SetName("");\r
249             }\r
250             var lines = Max(friendLines, enemyLines);\r
251             for (var i = 0; i < lines; i++)\r
252             {\r
253                 var panel = _panelList[i];\r
254                 if (panel.Visible)\r
255                     continue;\r
256                 panel.Location = Scaler.Move(AutoScrollPosition.X, AutoScrollPosition.Y, 0, (int)panel.Tag);\r
257                 panel.Visible = true;\r
258             }\r
259             for (var i = lines; i < _panelList.Count; i++)\r
260                 _panelList[i].Visible = false;\r
261             ResumeLayout(); // スクロールバーの有無を決定する\r
262             var panelWidth = Max(ClientSize.Width, // スクロールバーの有無を反映した横幅\r
263                 _enemyLabels[0][1].Location.X + _enemyLabels.Max(labels => labels[1].Size.Width) - 1); // 敵の名前の右端\r
264             for (var i = 0; i < lines; i++)\r
265                 _panelList[i].Width = panelWidth;\r
266             _informationPanel.Location = Scaler.Move(AutoScrollPosition.X, AutoScrollPosition.Y, 0, 20);\r
267             _informationPanel.Visible = true;\r
268             UpdateCellInfo(_cellInfo);\r
269         }\r
270 \r
271         private string GetEquipString(ShipStatus ship)\r
272         {\r
273             var result =\r
274                 (from i in Enumerable.Range(0, ship.Slot.Count)\r
275                     let item = ship.Slot[i]\r
276                     where !item.Empty\r
277                     select item.Spec.Name +\r
278                            (item.Spec.IsAircraft && ship.OnSlot.Length > 0 && ship.Spec.MaxEq.Length > 0\r
279                                ? $"{ship.OnSlot[i]}/{ship.Spec.MaxEq[i]}"\r
280                                : ""));\r
281             if (ship.SlotEx.Id > 0)\r
282                 result = result.Concat(new[] {ship.SlotEx.Spec.Name});\r
283             return string.Join("\r\n", result);\r
284         }\r
285 \r
286         private string ShortenName(string name)\r
287         {\r
288             return new Regex(@"\(elite\)|\(flagship\)").Replace(name,\r
289                 match => match.Value == "(elite)" ? "(e)" : "(f)");\r
290         }\r
291 \r
292         private void ShowResultRank(BattleResultRank rank)\r
293         {\r
294             var result = new[] {"完全S", "勝利S", "勝利A", "勝利B", "敗北C", "敗北D", "敗北E"};\r
295             _rankLabel.Text = result[(int)rank];\r
296             _supportLabel.Text = _supportType;\r
297         }\r
298 \r
299         public void UpdateCellInfo(CellInfo cellInfo)\r
300         {\r
301             _cellLabel.Text = (Spoilers & Spoiler.NextCell) == 0 ? cellInfo.Current : cellInfo.Next;\r
302             _cellLabel.Location = new Point(ClientSize.Width - _cellLabel.Width - 2, 4);\r
303         }\r
304 \r
305         private void CreateLabels()\r
306         {\r
307             _phaseLabel = new Label\r
308             {\r
309                 Location = new Point(4, 4),\r
310                 Size = new Size(31, 14)\r
311             };\r
312             _phaseLabel.Click += PhaseLabelClick;\r
313             Controls.Add(_phaseLabel);\r
314             _rankLabel = new Label\r
315             {\r
316                 Location = new Point(37, 4),\r
317                 Size = new Size(42, 12)\r
318             };\r
319             Controls.Add(_rankLabel);\r
320             _supportLabel = new Label\r
321             {\r
322                 Location = new Point(77, 4),\r
323                 AutoSize = true\r
324             };\r
325             Controls.Add(_supportLabel);\r
326             _cellLabel = new Label\r
327             {\r
328                 Location = new Point(0, 4),\r
329                 AutoSize = true\r
330             };\r
331             Controls.Add(_cellLabel);\r
332             for (var i = 0; i < 13; i++)\r
333             {\r
334                 var y = LineHeight * i + 38;\r
335                 var panel = new Panel\r
336                 {\r
337                     Location = new Point(0, y),\r
338                     Size = new Size(0, LineHeight),\r
339                     BackColor = ShipLabel.ColumnColors[i % 2],\r
340                     Visible = false,\r
341                     Tag = y\r
342                 };\r
343                 _panelList.Add(panel);\r
344 \r
345                 var friend = new[]\r
346                 {\r
347                     new ShipLabel\r
348                     {\r
349                         Location = new Point(101, 0),\r
350                         AutoSize = true,\r
351                         AnchorRight = true,\r
352                         MinimumSize = new Size(0, LineHeight),\r
353                         TextAlign = ContentAlignment.MiddleLeft,\r
354                         Cursor = Cursors.Hand\r
355                     },\r
356                     new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
357                 };\r
358                 _friendLabels.Add(friend);\r
359                 _hpLabels.Add(friend[0]);\r
360                 friend[0].Click += HpLabelClickHandler;\r
361                 var enemy = new[]\r
362                 {\r
363                     new ShipLabel\r
364                     {\r
365                         Location = new Point(119, 0),\r
366                         AutoSize = true,\r
367                         MinimumSize = new Size(0, LineHeight),\r
368                         TextAlign = ContentAlignment.MiddleLeft\r
369                     },\r
370                     new ShipLabel {Location = new Point(164, 2), AutoSize = true}\r
371                 };\r
372                 _enemyLabels.Add(enemy);\r
373                 foreach (var label in friend.Concat(enemy))\r
374                 {\r
375                     panel.Controls.Add(label);\r
376                     label.BackColor = ShipLabel.ColumnColors[i % 2];\r
377                 }\r
378                 Controls.Add(panel);\r
379             }\r
380         }\r
381 \r
382         protected override void OnMouseWheel(MouseEventArgs e)\r
383         {\r
384             if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)\r
385             {\r
386                 VScroll = false;\r
387                 OnMouseWheel(e);\r
388                 VScroll = true;\r
389                 return;\r
390             }\r
391             base.OnMouseWheel(e);\r
392         }\r
393 \r
394         private class InformationPanel : PanelWithToolTip\r
395         {\r
396             private readonly Label[] _formation;\r
397             private readonly Label[] _fighterPower;\r
398 \r
399             public InformationPanel()\r
400             {\r
401                 Visible = false;\r
402                 Size = new Size(206, 16);\r
403                 Controls.AddRange(_formation = new[]\r
404                 {\r
405                     new Label\r
406                     {\r
407                         Location = new Point(47, 2),\r
408                         Size = new Size(29, 12)\r
409                     },\r
410                     new Label\r
411                     {\r
412                         Location = new Point(75, 2),\r
413                         Size = new Size(29, 12)\r
414                     },\r
415                     new Label\r
416                     {\r
417                         Location = new Point(1, 2),\r
418                         Size = new Size(48, 12),\r
419                         TextAlign = ContentAlignment.MiddleCenter\r
420                     }\r
421                 });\r
422                 Controls.AddRange(_fighterPower = new[]\r
423                 {\r
424                     new Label\r
425                     {\r
426                         Location = new Point(162, 2),\r
427                         Size = new Size(23, 12),\r
428                         TextAlign = ContentAlignment.MiddleRight\r
429                     },\r
430                     new Label\r
431                     {\r
432                         Location = new Point(183, 2),\r
433                         Size = new Size(23, 12),\r
434                         TextAlign = ContentAlignment.MiddleRight\r
435                     },\r
436                     new Label\r
437                     {\r
438                         Location = new Point(110, 2),\r
439                         Size = new Size(53, 12)\r
440                     }\r
441                 });\r
442                 // ReSharper disable once VirtualMemberCallInConstructor\r
443                 BackColor = ShipLabel.ColumnColors[1];\r
444             }\r
445 \r
446             public void SetInformation(BattleInfo battleInfo)\r
447             {\r
448                 _formation[0].Text = FormationName(battleInfo.Formation[0]);\r
449                 _formation[1].Text = FormationName(battleInfo.Formation[1]);\r
450                 _formation[2].Text = new[] {"同航戦", "反航戦", "T字有利", "T字不利"}[battleInfo.Formation[2] - 1];\r
451 \r
452                 if (battleInfo.AirControlLevel == -1)\r
453                 {\r
454                     if (battleInfo.BattleState == BattleState.Night)\r
455                         return;\r
456                     foreach (var label in _fighterPower)\r
457                         label.Visible = false;\r
458                     return;\r
459                 }\r
460                 var fp = battleInfo.FighterPower;\r
461                 _fighterPower[0].Text = fp[0].ToString("D");\r
462                 ToolTip.SetToolTip(_fighterPower[0], fp[0] == fp[1] ? "" : $"{fp[0]}~{fp[1]}");\r
463                 var efp = battleInfo.EnemyFighterPower;\r
464                 _fighterPower[1].Text = efp.AirCombat + efp.UnknownMark;\r
465                 ToolTip.SetToolTip(_fighterPower[1],\r
466                     efp.AirCombat == efp.Interception ? "" : "防空:" + efp.Interception + efp.UnknownMark);\r
467                 _fighterPower[2].Text =\r
468                     new[] {"", "制空均衡", "制空確保", "航空優勢", "航空劣勢", "制空喪失"}[battleInfo.AirControlLevel + 1];\r
469                 foreach (var label in _fighterPower)\r
470                     label.Visible = true;\r
471             }\r
472 \r
473             private string FormationName(int formation)\r
474             {\r
475                 switch (formation)\r
476                 {\r
477                     case 1:\r
478                         return "単縦";\r
479                     case 2:\r
480                         return "複縦";\r
481                     case 3:\r
482                         return "輪形";\r
483                     case 4:\r
484                         return "梯形";\r
485                     case 5:\r
486                         return "単横";\r
487                     case 6:\r
488                         return "警戒";\r
489                     case 11:\r
490                         return "第一";\r
491                     case 12:\r
492                         return "第二";\r
493                     case 13:\r
494                         return "第三";\r
495                     case 14:\r
496                         return "第四";\r
497                     default:\r
498                         return "";\r
499                 }\r
500             }\r
501         }\r
502     }\r
503 }