OSDN Git Service

a39a563e33339ac700348bbfb051bfe13d784ed9
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / MainWindow / ShipInfoPanel.cs
1 using System;\r
2 using System.Drawing;\r
3 using System.Linq;\r
4 using System.Windows.Forms;\r
5 using KancolleSniffer.Model;\r
6 \r
7 namespace KancolleSniffer.View.MainWindow\r
8 {\r
9     public class ShipInfoPanel : PanelWithToolTip, IUpdateTimers\r
10     {\r
11         private readonly Panel _combinedFleet = new Panel\r
12         {\r
13             Location = new Point(0, 0),\r
14             Size = new Size(220, 113),\r
15             Visible = false\r
16         };\r
17 \r
18         private readonly Panel _7Ships = new Panel\r
19         {\r
20             Location = new Point(0, 0),\r
21             Size = new Size(220, 113),\r
22             Visible = false\r
23         };\r
24 \r
25         private readonly Panel _battleInfo = new Panel\r
26         {\r
27             Location = new Point(59, 116),\r
28             Size = new Size(157, 14),\r
29             Visible = false\r
30         };\r
31 \r
32         private readonly Label _presetAkashiTimer = new Label\r
33         {\r
34             Location = new Point(2, 3),\r
35             Size = new Size(32, 12),\r
36             BackColor = CustomColors.ColumnColors.Bright\r
37         };\r
38 \r
39         public LinkLabel Guide { get; } = new LinkLabel\r
40         {\r
41             AutoSize = true,\r
42             Font = new Font("MS UI Gothic", 9.75F, FontStyle.Regular, GraphicsUnit.Point, 128),\r
43             LinkArea = new LinkArea(0, 0),\r
44             Location = new Point(31, 51),\r
45             Text = "右クリックでメニューが出ます。"\r
46         };\r
47 \r
48         private readonly Label _enemyFighterPower = new Label\r
49         {\r
50             Location = new Point(129, 1),\r
51             Size = new Size(29, 12),\r
52             TextAlign = ContentAlignment.MiddleRight\r
53         };\r
54 \r
55         private readonly Label _enemyFighterPowerCaption = new Label\r
56         {\r
57             AutoSize = true,\r
58             Location = new Point(90, 1),\r
59             Text = "敵制空"\r
60         };\r
61 \r
62         private readonly Label _formation = new Label\r
63         {\r
64             Location = new Point(40, 1),\r
65             Size = new Size(48, 12)\r
66         };\r
67 \r
68         private readonly Label _resultRank = new Label\r
69         {\r
70             Location = new Point(1, 1),\r
71             Size = new Size(42, 12),\r
72             TabIndex = 0,\r
73             Text = "判定"\r
74         };\r
75 \r
76         private readonly Label _lineOfSight = new Label\r
77         {\r
78             Location = new Point(85, 117),\r
79             Size = new Size(38, 12),\r
80             Text = "0.0",\r
81             TextAlign = ContentAlignment.MiddleRight\r
82         };\r
83 \r
84         private readonly Label _lineOfSightCaption = new Label\r
85         {\r
86             AutoSize = true,\r
87             Location = new Point(59, 117),\r
88             Text = "索敵"\r
89         };\r
90 \r
91         private readonly Label _fighterPower = new Label\r
92         {\r
93             Location = new Point(28, 117),\r
94             Size = new Size(29, 12),\r
95             Text = "0",\r
96             TextAlign = ContentAlignment.MiddleRight\r
97         };\r
98 \r
99         private readonly Label _fighterPowerCaption = new Label\r
100         {\r
101             AutoSize = true,\r
102             Location = new Point(2, 117),\r
103             Text = "制空"\r
104         };\r
105 \r
106         private readonly Label _condTimerCaption = new Label\r
107         {\r
108             Location = new Point(128, 117),\r
109             Size = new Size(60, 12)\r
110         };\r
111 \r
112         private readonly Label _condTimer = new Label\r
113         {\r
114             AutoSize = true,\r
115             Location = new Point(186, 117)\r
116         };\r
117 \r
118         private readonly MainShipLabels _mainLabels = new MainShipLabels();\r
119 \r
120         public UpdateContext Context { get; set; }\r
121 \r
122         public int CurrentFleet { get; set; }\r
123 \r
124         public bool CombinedFleet { get; set; }\r
125 \r
126         public Action<int> ShowShipOnList { get; set; }\r
127 \r
128         public ShipInfoPanel()\r
129         {\r
130             Controls.AddRange(new Control[] {Guide, _presetAkashiTimer, _combinedFleet, _7Ships});\r
131             BorderStyle = BorderStyle.FixedSingle;\r
132             _mainLabels.CreateAllShipLabels(new MainShipPanels\r
133             {\r
134                 PanelShipInfo = this,\r
135                 Panel7Ships = _7Ships,\r
136                 PanelCombinedFleet = _combinedFleet\r
137             }, ShipClickHandler);\r
138             _battleInfo.Controls.AddRange(new Control[]\r
139             {\r
140                 _enemyFighterPower, _enemyFighterPowerCaption, _formation, _resultRank\r
141             });\r
142             Controls.AddRange(new Control[]\r
143             {\r
144                 _battleInfo,\r
145                 _lineOfSight, _lineOfSightCaption, _fighterPower, _fighterPowerCaption, _condTimer, _condTimerCaption\r
146             });\r
147             _resultRank.Click += ResultRankClick;\r
148             Size = new Size(220, 134);\r
149         }\r
150 \r
151         private void ShipClickHandler(object sender, EventArgs e)\r
152         {\r
153             var idx = (int)((Control)sender).Tag;\r
154             var ship = (CombinedFleet\r
155                 ? Context.Sniffer.Fleets[0].Ships.Concat(Context.Sniffer.Fleets[1].Ships)\r
156                 : Context.Sniffer.Fleets[CurrentFleet].Ships).ElementAt(idx);\r
157             if (!ship.Empty)\r
158                 ShowShipOnList(ship.Id);\r
159         }\r
160 \r
161         public void ToggleHpPercent()\r
162         {\r
163             _mainLabels.ToggleHpPercent();\r
164         }\r
165 \r
166         public bool ShowHpInPercent => _mainLabels.ShowHpInPercent;\r
167 \r
168         private bool _inSortie;\r
169 \r
170         public void SetCurrentFleet()\r
171         {\r
172             var inSortie = Context.Sniffer.InSortie;\r
173             if (_inSortie || inSortie == -1)\r
174             {\r
175                 _inSortie = inSortie != -1;\r
176                 return;\r
177             }\r
178             _inSortie = true;\r
179             if (inSortie == 10)\r
180             {\r
181                 CombinedFleet = true;\r
182                 CurrentFleet = 0;\r
183             }\r
184             else\r
185             {\r
186                 CombinedFleet = false;\r
187                 CurrentFleet = inSortie;\r
188             }\r
189             SetCombined();\r
190         }\r
191 \r
192         private bool _prevCombined;\r
193 \r
194         private void SetCombined()\r
195         {\r
196             if (Context.Sniffer.IsCombinedFleet && !_prevCombined)\r
197             {\r
198                 CombinedFleet = true;\r
199                 CurrentFleet = 0;\r
200             }\r
201             _prevCombined = Context.Sniffer.IsCombinedFleet;\r
202         }\r
203 \r
204         public new void Update()\r
205         {\r
206             var ships = Context.Sniffer.Fleets[CurrentFleet].ActualShips;\r
207             _7Ships.Visible = ships.Count == 7;\r
208             _mainLabels.SetShipLabels(ships);\r
209             ShowCombinedFleet();\r
210             _presetAkashiTimer.Visible = Context.Config.UsePresetAkashi;\r
211             UpdateAkashiTimer();\r
212             UpdateFighterPower(IsCombinedFighterPower);\r
213             UpdateLoS();\r
214             UpdateCondTimers();\r
215         }\r
216 \r
217         private void ShowCombinedFleet()\r
218         {\r
219             if (!Context.Sniffer.IsCombinedFleet)\r
220                 CombinedFleet = false;\r
221             _combinedFleet.Visible = CombinedFleet;\r
222             if (CombinedFleet)\r
223             {\r
224                 _mainLabels.SetCombinedShipLabels(Context.Sniffer.Fleets[0].ActualShips,\r
225                     Context.Sniffer.Fleets[1].ActualShips);\r
226             }\r
227         }\r
228 \r
229         private bool IsCombinedFighterPower => CombinedFleet &&\r
230                                                (Context.Sniffer.Battle.BattleState == BattleState.None ||\r
231                                                 Context.Sniffer.Battle.EnemyIsCombined);\r
232 \r
233         private void UpdateFighterPower(bool combined)\r
234         {\r
235             var fleets = Context.Sniffer.Fleets;\r
236             var fp = combined\r
237                 ? fleets[0].FighterPower + fleets[1].FighterPower\r
238                 : fleets[CurrentFleet].FighterPower;\r
239             _fighterPower.Text = fp.Min.ToString("D");\r
240             var cr = combined\r
241                 ? fleets[0].ContactTriggerRate + fleets[1].ContactTriggerRate\r
242                 : fleets[CurrentFleet].ContactTriggerRate;\r
243             var text = "制空: " + (fp.Diff ? fp.RangeString : fp.Min.ToString()) +\r
244                        $" 触接: {cr * 100:f1}";\r
245             ToolTip.SetToolTip(_fighterPower, text);\r
246             ToolTip.SetToolTip(_fighterPowerCaption, text);\r
247         }\r
248 \r
249         private void UpdateLoS()\r
250         {\r
251             var fleet = Context.Sniffer.Fleets[CurrentFleet];\r
252             _lineOfSight.Text = RoundDown(fleet.GetLineOfSights(1)).ToString("F1");\r
253             var text = $"係数2: {RoundDown(fleet.GetLineOfSights(2)):F1}\r\n" +\r
254                        $"係数3: {RoundDown(fleet.GetLineOfSights(3)):F1}\r\n" +\r
255                        $"係数4: {RoundDown(fleet.GetLineOfSights(4)):F1}";\r
256             ToolTip.SetToolTip(_lineOfSight, text);\r
257             ToolTip.SetToolTip(_lineOfSightCaption, text);\r
258         }\r
259 \r
260         private double RoundDown(double number)\r
261         {\r
262             return Math.Floor(number * 10) / 10.0;\r
263         }\r
264 \r
265         public void UpdateBattleInfo()\r
266         {\r
267             ResetBattleInfo();\r
268             if (Context.Sniffer.Battle.BattleState == BattleState.None)\r
269                 return;\r
270             _battleInfo.BringToFront();\r
271             var battle = Context.Sniffer.Battle;\r
272             _formation.Text = new[] {"同航戦", "反航戦", "T字有利", "T字不利"}[battle.Formation[2] - 1];\r
273             UpdateBattleFighterPower();\r
274             if ((Context.Config.Spoilers & Spoiler.ResultRank) != 0)\r
275                 ShowResultRank();\r
276         }\r
277 \r
278         private void ResetBattleInfo()\r
279         {\r
280             _formation.Text = "";\r
281             _enemyFighterPower.Text = "";\r
282             _fighterPower.ForeColor = DefaultForeColor;\r
283             _fighterPowerCaption.Text = "制空";\r
284             _resultRank.Text = "判定";\r
285             _battleInfo.Visible = Context.Sniffer.Battle.BattleState != BattleState.None;\r
286         }\r
287 \r
288         private void UpdateBattleFighterPower()\r
289         {\r
290             UpdateEnemyFighterPower();\r
291             var battle = Context.Sniffer.Battle;\r
292             _fighterPower.ForeColor = AirControlLevelColor(battle);\r
293             _fighterPowerCaption.Text = AirControlLevelString(battle);\r
294             if (battle.BattleState == BattleState.AirRaid)\r
295             {\r
296                 UpdateAirRaidFighterPower();\r
297             }\r
298             else\r
299             {\r
300                 UpdateFighterPower(Context.Sniffer.IsCombinedFleet && battle.EnemyIsCombined);\r
301             }\r
302         }\r
303 \r
304         private void UpdateEnemyFighterPower()\r
305         {\r
306             var fp = Context.Sniffer.Battle.EnemyFighterPower;\r
307             _enemyFighterPower.Text = fp.AirCombat + fp.UnknownMark;\r
308             var toolTip = fp.AirCombat == fp.Interception ? "" : "防空: " + fp.Interception + fp.UnknownMark;\r
309             ToolTip.SetToolTip(_enemyFighterPower, toolTip);\r
310             ToolTip.SetToolTip(_enemyFighterPowerCaption, toolTip);\r
311         }\r
312 \r
313         private void UpdateAirRaidFighterPower()\r
314         {\r
315             var fp = Context.Sniffer.Battle.FighterPower;\r
316             _fighterPower.Text = fp.Min.ToString();\r
317             var toolTop = fp.Diff ? fp.RangeString : "";\r
318             ToolTip.SetToolTip(_fighterPower, toolTop);\r
319             ToolTip.SetToolTip(_fighterPowerCaption, toolTop);\r
320         }\r
321 \r
322         private static Color AirControlLevelColor(BattleInfo battle)\r
323         {\r
324             return new[]\r
325                 {DefaultForeColor, DefaultForeColor, CUDColors.Blue, CUDColors.Green, CUDColors.Orange, CUDColors.Red}[\r
326                 battle.BattleState == BattleState.Night ? 0 : battle.AirControlLevel + 1];\r
327         }\r
328 \r
329         private static string AirControlLevelString(BattleInfo battle)\r
330         {\r
331             return new[] {"制空", "拮抗", "確保", "優勢", "劣勢", "喪失"}[\r
332                 battle.BattleState == BattleState.Night ? 0 : battle.AirControlLevel + 1];\r
333         }\r
334 \r
335         private void ShowResultRank()\r
336         {\r
337             var result = new[] {"完全S", "勝利S", "勝利A", "勝利B", "敗北C", "敗北D", "敗北E"};\r
338             _resultRank.Text = result[(int)Context.Sniffer.Battle.ResultRank];\r
339         }\r
340 \r
341         private void ResultRankClick(object sender, EventArgs e)\r
342         {\r
343             ShowResultRank();\r
344         }\r
345 \r
346         private void UpdateCondTimers()\r
347         {\r
348             DateTime timer;\r
349             if (CombinedFleet)\r
350             {\r
351                 var timer1 = Context.Sniffer.GetConditionTimer(0);\r
352                 var timer2 = Context.Sniffer.GetConditionTimer(1);\r
353                 timer = timer2 > timer1 ? timer2 : timer1;\r
354             }\r
355             else\r
356             {\r
357                 timer = Context.Sniffer.GetConditionTimer(CurrentFleet);\r
358             }\r
359             if (timer == DateTime.MinValue)\r
360             {\r
361                 _condTimerCaption.Text = "";\r
362                 _condTimer.Text = "";\r
363                 return;\r
364             }\r
365             var span = TimeSpan.FromSeconds(Math.Ceiling((timer - Context.GetStep().Now).TotalSeconds));\r
366             if (span >= TimeSpan.FromMinutes(9) && Context.Config.NotifyConditions.Contains(40))\r
367             {\r
368                 _condTimerCaption.Text = "cond40まで";\r
369                 _condTimer.Text = (span - TimeSpan.FromMinutes(9)).ToString(@"mm\:ss");\r
370                 _condTimer.ForeColor = DefaultForeColor;\r
371             }\r
372             else\r
373             {\r
374                 _condTimerCaption.Text = "cond49まで";\r
375                 _condTimer.Text = (span >= TimeSpan.Zero ? span : TimeSpan.Zero).ToString(@"mm\:ss");\r
376                 _condTimer.ForeColor = span <= TimeSpan.Zero ? CUDColors.Red : DefaultForeColor;\r
377             }\r
378         }\r
379 \r
380         public Label AkashiRepairTimer { get; set; }\r
381 \r
382         public void UpdateTimers()\r
383         {\r
384             UpdateAkashiTimer();\r
385             UpdatePresetAkashiTimer();\r
386         }\r
387 \r
388         private void UpdateAkashiTimer()\r
389         {\r
390             if (Context.Config.UsePresetAkashi)\r
391                 UpdatePresetAkashiTimer();\r
392             _mainLabels.SetAkashiTimer(Context.Sniffer.Fleets[CurrentFleet].ActualShips,\r
393                 Context.Sniffer.AkashiTimer.GetTimers(CurrentFleet, Context.GetStep().Now));\r
394         }\r
395 \r
396         private void UpdatePresetAkashiTimer()\r
397         {\r
398             var now = Context.GetStep().Now;\r
399             var akashi = Context.Sniffer.AkashiTimer;\r
400             var span = akashi.GetPresetDeckTimer(now);\r
401             var color = span == TimeSpan.Zero && akashi.CheckPresetRepairing() ? CUDColors.Red : DefaultForeColor;\r
402             var text = span == TimeSpan.MinValue ? "" : span.ToString(@"mm\:ss");\r
403             AkashiRepairTimer.ForeColor = color;\r
404             AkashiRepairTimer.Text = text;\r
405             if (akashi.CheckPresetRepairing() && !akashi.CheckRepairing(CurrentFleet, now))\r
406             {\r
407                 _presetAkashiTimer.ForeColor = color;\r
408                 _presetAkashiTimer.Text = text;\r
409             }\r
410             else\r
411             {\r
412                 _presetAkashiTimer.ForeColor = DefaultForeColor;\r
413                 _presetAkashiTimer.Text = "";\r
414             }\r
415         }\r
416     }\r
417 }