OSDN Git Service

4月23日に行われたプロトコル変更に対応する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / MainForm.cs
1 // Copyright (C) 2013, 2014 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
2 // \r
3 // This program is part of KancolleSniffer.\r
4 //\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify\r
6 // it under the terms of the GNU General Public License as published by\r
7 // the Free Software Foundation, either version 3 of the License, or\r
8 // (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 using System;\r
19 using System.Drawing;\r
20 using System.IO;\r
21 using System.Linq;\r
22 using System.Windows.Forms;\r
23 using Codeplex.Data;\r
24 using Fiddler;\r
25 \r
26 namespace KancolleSniffer\r
27 {\r
28     public partial class MainForm : Form\r
29     {\r
30         private readonly Sniffer _sniffer = new Sniffer();\r
31         private readonly dynamic _wmp = Activator.CreateInstance(Type.GetTypeFromProgID("WMPlayer.OCX.7"));\r
32         private readonly Config _config = new Config();\r
33         private readonly ConfigDialog _configDialog = new ConfigDialog();\r
34         private readonly int _labelRightDistance;\r
35         private int _currentFleet;\r
36         private readonly Label[] _labelCheckFleets;\r
37         private bool _started;\r
38 \r
39         public MainForm()\r
40         {\r
41             InitializeComponent();\r
42             FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;\r
43             _wmp.PlayStateChange += new EventHandler(_wmp_PlayStateChange);\r
44             _configDialog.Tag = _config;\r
45             _labelRightDistance = labelHP1.Parent.Width - labelHP1.Right;\r
46             _labelCheckFleets = new[] {labelCheckFleet1, labelCheckFleet2, labelCheckFleet3, labelCheckFleet4};\r
47             var i = 0;\r
48             foreach (var label in new[] {labelFleet1, labelFleet2, labelFleet3, labelFleet4})\r
49                 label.Tag = i++;\r
50         }\r
51 \r
52         private void FiddlerApplication_AfterSessionComplete(Session oSession)\r
53         {\r
54             if (!oSession.bHasResponse || !oSession.uriContains("/kcsapi/api_"))\r
55                 return;\r
56             var response = oSession.GetResponseBodyAsString();\r
57             if (!response.StartsWith("svdata="))\r
58                 return;\r
59             response = response.Remove(0, "svdata=".Length);\r
60             var json = DynamicJson.Parse(response);\r
61             var request = oSession.GetRequestBodyAsString();\r
62             var update = (Sniffer.Update)_sniffer.Sniff(oSession.url, request, json);\r
63             if (update == Sniffer.Update.Start)\r
64             {\r
65                 Invoke(new Action(() => {labelLogin.Visible = false;}));\r
66                 _started = true;\r
67                 return;\r
68             }\r
69             if (!_started)\r
70                 return;\r
71             Action action = null;\r
72             if ((update & Sniffer.Update.Item) != 0)\r
73                 action += UpdateItemInfo;\r
74             if ((update & Sniffer.Update.Timer) != 0)\r
75                 action += UpdateTimers;\r
76             if ((update & Sniffer.Update.NDock) != 0)\r
77                 action += UpdateNDocLabels;\r
78             if ((update & Sniffer.Update.Mission) != 0)\r
79                 action += UpdateMissionLabels;\r
80             if ((update & Sniffer.Update.QuestList) != 0)\r
81                 action += UpdateQuestList;\r
82             if ((update & Sniffer.Update.Ship) != 0)\r
83                 action += UpdateShipInfo;\r
84             Invoke(action);\r
85         }\r
86 \r
87         private void MainForm_Load(object sender, EventArgs e)\r
88         {\r
89             _config.Load();\r
90             ApplyConfig();\r
91             FiddlerApplication.Startup(0, FiddlerCoreStartupFlags.RegisterAsSystemProxy);\r
92         }\r
93 \r
94         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)\r
95         {\r
96             FiddlerApplication.Shutdown();\r
97             _config.Save();\r
98         }\r
99 \r
100         private void labelHP_SizeChanged(object sender, EventArgs e)\r
101         {\r
102             var label = (Label)sender;\r
103             label.Location = new Point(label.Parent.Width - _labelRightDistance - label.Width, label.Top);\r
104         }\r
105 \r
106         private void notifyIconMain_MouseDoubleClick(object sender, MouseEventArgs e)\r
107         {\r
108             if (WindowState == FormWindowState.Minimized)\r
109                 WindowState = FormWindowState.Normal;\r
110             Activate();\r
111         }\r
112 \r
113         private void ExitToolStripMenuItem_Click(object sender, EventArgs e)\r
114         {\r
115             Application.Exit();\r
116         }\r
117 \r
118 \r
119         private void ConfigToolStripMenuItem_Click(object sender, EventArgs e)\r
120         {\r
121             if (_configDialog.ShowDialog(this) == DialogResult.OK)\r
122                 ApplyConfig();\r
123         }\r
124 \r
125         private void ApplyConfig()\r
126         {\r
127             TopMost = _config.TopMost;\r
128             _wmp.settings.volume = _config.SoundVolume;\r
129             _sniffer.Item.MarginShips = _config.MarginShips;\r
130         }\r
131 \r
132         private void timerMain_Tick(object sender, EventArgs e)\r
133         {\r
134             if (_started)\r
135                 UpdateTimers();\r
136         }\r
137 \r
138         private void UpdateItemInfo()\r
139         {\r
140             var item = _sniffer.Item;\r
141             labelNumOfShips.Text = string.Format("{0:D}/{1:D}", item.NowShips, item.MaxShips);\r
142             labelNumOfShips.ForeColor = item.TooManyShips ? Color.Red : Color.Black;\r
143             if (item.NeedRing)\r
144             {\r
145                 var message = string.Format("残り{0:D}隻", _sniffer.Item.MaxShips - _sniffer.Item.NowShips);\r
146                 Ring("艦娘が多すぎます", message, _config.MaxShipsSoundFile);\r
147                 item.NeedRing = false;\r
148             }\r
149             labelNumOfEquips.Text = string.Format("{0:D}/{1:D}", item.NowItems, item.MaxItems);\r
150             labelNumOfBuckets.Text = item.NumBuckets.ToString("D");\r
151         }\r
152 \r
153         private void UpdateMissionLabels()\r
154         {\r
155             foreach (var entry in\r
156                 new[] {labelMissionName1, labelMissionName2, labelMissionName3}.Zip(_sniffer.Missions,\r
157                     (label, mission) => new {label, mission.Name}))\r
158                 entry.label.Text = entry.Name;\r
159         }\r
160 \r
161         private void UpdateNDocLabels()\r
162         {\r
163             foreach (var entry in\r
164                 new[] {labelRepairShip1, labelRepairShip2, labelRepairShip3, labelRepairShip4}.Zip(_sniffer.NDock,\r
165                     (label, ndock) => new {label, ndock.Name}))\r
166                 entry.label.Text = entry.Name;\r
167         }\r
168 \r
169         private void UpdateShipInfo()\r
170         {\r
171             var name = new[] {labelShip1, labelShip2, labelShip3, labelShip4, labelShip5, labelShip6};\r
172             var lv = new[] {labelLv1, labelLv2, labelLv3, labelLv4, labelLv5, labelLv6};\r
173             var hp = new[] {labelHP1, labelHP2, labelHP3, labelHP4, labelHP5, labelHP6};\r
174             var cond = new[] {labelCond1, labelCond2, labelCond3, labelCond4, labelCond5, labelCond6};\r
175             var next = new[] {labelNextLv1, labelNextLv2, labelNextLv3, labelNextLv4, labelNextLv5, labelNextLv6};\r
176 \r
177             var statuses = _sniffer.GetShipStatuses(_currentFleet);\r
178             for (var i = 0; i < name.Length; i++)\r
179             {\r
180                 var stat = statuses[i];\r
181                 name[i].Text = stat.Name;\r
182                 lv[i].Text = stat.Level.ToString("D");\r
183                 SetHpLavel(hp[i], stat.NowHp, stat.MaxHp);\r
184                 if (stat.Name == null)\r
185                 {\r
186                     cond[i].Text = "0";\r
187                     cond[i].BackColor = DefaultBackColor;\r
188                 }\r
189                 else\r
190                     SetCondLabel(cond[i], stat.Cond);\r
191                 next[i].Text = stat.ExpToNext.ToString("D");\r
192             }\r
193             labelAirSuperiority.Text = _sniffer.GetAirSuperiority(_currentFleet).ToString("D");\r
194             UpdateChargeInfo();\r
195         }\r
196 \r
197         private void UpdateChargeInfo()\r
198         {\r
199             var fuel = new[] {labelFuel1, labelFuel2, labelFuel3, labelFuel4};\r
200             var bull = new[] {labelBull1, labelBull2, labelBull3, labelBull4};\r
201 \r
202             for (var i = 0; i < fuel.Length; i++)\r
203             {\r
204                 var stat = _sniffer.ChargeStatuses[i];\r
205                 fuel[i].ImageIndex = stat.Fuel;\r
206                 bull[i].ImageIndex = stat.Bull;\r
207             }\r
208         }\r
209 \r
210         private void SetHpLavel(Label label, int now, int max)\r
211         {\r
212             label.Text = string.Format("{0:D}/{1:D}", now, max);\r
213             var damage = max == 0 ? 1 : (double)now / max;\r
214             label.BackColor = damage > 0.75\r
215                 ? DefaultBackColor\r
216                 : damage > 0.5 ? Color.FromArgb(255, 240, 240, 100) : damage > 0.25 ? Color.Orange : Color.Red;\r
217         }\r
218 \r
219         private void SetCondLabel(Label label, int cond)\r
220         {\r
221             label.Text = cond.ToString("D");\r
222             label.BackColor = cond >= 50\r
223                 ? Color.Yellow\r
224                 : cond >= 30\r
225                     ? DefaultBackColor\r
226                     : cond >= 20 ? Color.Orange : Color.Red;\r
227         }\r
228 \r
229         private void UpdateTimers()\r
230         {\r
231             foreach (var entry in\r
232                 new[] {labelMission1, labelMission2, labelMission3}.Zip(_sniffer.Missions,\r
233                     (label, mission) => new {label, mission.Name, mission.Timer}))\r
234             {\r
235                 entry.Timer.Update();\r
236                 SetTimerLabel(entry.label, entry.Timer);\r
237                 if (!entry.Timer.NeedRing)\r
238                     continue;\r
239                 Ring("遠征が終わりました", entry.Name, _config.MissionSoundFile);\r
240                 entry.Timer.NeedRing = false;\r
241             }\r
242             foreach (var entry in\r
243                 new[] {labelRepair1, labelRepair2, labelRepair3, labelRepair4}.Zip(_sniffer.NDock,\r
244                     (label, ndock) => new {label, ndock.Name, ndock.Timer}))\r
245             {\r
246                 entry.Timer.Update();\r
247                 SetTimerLabel(entry.label, entry.Timer);\r
248                 if (!entry.Timer.NeedRing)\r
249                     continue;\r
250                 Ring("入渠が終わりました", entry.Name, _config.NDockSoundFile);\r
251                 entry.Timer.NeedRing = false;\r
252             }\r
253             var kdock = new[] {labelConstruct1, labelConstruct2, labelConstruct3, labelConstruct4};\r
254             for (var i = 0; i < kdock.Length; i++)\r
255             {\r
256                 var timer = _sniffer.KDock[i];\r
257                 timer.Update();\r
258                 SetTimerLabel(kdock[i], timer);\r
259                 if (!timer.NeedRing)\r
260                     continue;\r
261                 Ring("建造が終わりました", string.Format("第{0:D}ドック", i + 1), _config.KDockSoundFile);\r
262                 timer.NeedRing = false;\r
263             }\r
264             UpdateCondTimers();\r
265         }\r
266 \r
267         private void SetTimerLabel(Label label, RingTimer timer)\r
268         {\r
269             if (timer.NeedRing)\r
270                 label.ForeColor = Color.Red;\r
271             if (!timer.IsSet)\r
272                 label.ForeColor = Color.Black;\r
273             label.Text = timer.ToString();\r
274         }\r
275 \r
276         private void UpdateCondTimers()\r
277         {\r
278             var now = DateTime.Now;\r
279             foreach (var entry in\r
280                 new[] {labelCondTimer1, labelCondTimer2, labelCondTimer3}.Zip(_sniffer.GetRecoveryTimes(_currentFleet),\r
281                     (label, time) => new {label, time}))\r
282                 entry.label.Text = entry.time > now ? (entry.time - now).ToString(@"mm\:ss") : "00:00";\r
283         }\r
284 \r
285         private void UpdateQuestList()\r
286         {\r
287             var name = new[] {labelQuest1, labelQuest2, labelQuest3, labelQuest4, labelQuest5};\r
288             var progress = new[] {labelProgress1, labelProgress2, labelProgress3, labelProgress4, labelProgress5};\r
289 \r
290             for (var i = 0; i < name.Length; i++)\r
291             {\r
292                 if (i < _sniffer.Quests.Length)\r
293                 {\r
294                     name[i].Text = _sniffer.Quests[i].Name;\r
295                     progress[i].Text = string.Format("{0:D}%", _sniffer.Quests[i].Progress);\r
296                 }\r
297                 else\r
298                 {\r
299                     name[i].Text = progress[i].Text = "";\r
300                 }\r
301             }\r
302         }\r
303 \r
304         private void Ring(string baloonTitle, string baloonMessage, string soundFile)\r
305         {\r
306             if (_config.FlashWindow)\r
307                 Win32API.FlashWindow(Handle);\r
308             if (_config.ShowBaloonTip)\r
309                 notifyIconMain.ShowBalloonTip(20000, baloonTitle, baloonMessage, ToolTipIcon.Info);\r
310             if (_config.PlaySound && File.Exists(soundFile))\r
311             {\r
312                 _wmp.URL = soundFile;\r
313                 _wmp.controls.play();\r
314             }\r
315         }\r
316 \r
317         private void _wmp_PlayStateChange(object sender, EventArgs e)\r
318         {\r
319             if (_wmp.playState == 8) // MediaEnded\r
320                 _wmp.URL = ""; // 再生したファイルが差し替えできなくなるのを防ぐ。\r
321         }\r
322 \r
323         private void labelFleet_Click(object sender, EventArgs e)\r
324         {\r
325             var fleet = (int)((Label)sender).Tag;\r
326             if (_currentFleet == fleet)\r
327                 return;\r
328             _currentFleet = fleet;\r
329             foreach (var label in _labelCheckFleets)\r
330                 label.Visible = false;\r
331             _labelCheckFleets[fleet].Visible = true;\r
332             if (!_started)\r
333                 return;\r
334             UpdateShipInfo();\r
335             UpdateCondTimers();\r
336         }\r
337     }\r
338 }