]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/stand_gui.cpp
add first stages of GUI for standalone
[taylor/freespace2.git] / src / network / stand_gui.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9
10
11 #include "stand_gui.h"
12 #include "osregistry.h"
13
14 #include "wx/statline.h"
15 #include "wx/filename.h"
16 #include "wx/stdpaths.h"
17 #include "wx/utils.h"
18 #include "wx/msgdlg.h"
19 #include "wx/process.h"
20
21
22 // taken from psnet.h and psnet2.h
23 #ifdef MAKE_FS1
24         #define DEFAULT_GAME_PORT 4000
25 #elif defined(FS2_DEMO)
26         #define DEFAULT_GAME_PORT 7802
27 #else
28         #define DEFAULT_GAME_PORT 7808
29 #endif
30
31
32
33 IMPLEMENT_APP(StandaloneApp)
34
35 bool StandaloneApp::OnInit()
36 {
37         if ( !wxApp::OnInit() ) {
38                 return false;
39         }
40
41         std_client = new Standalone(NULL);
42
43         try {
44                 if ( !std_client->startFreeSpace() ) {
45                         throw "Unable to start FreeSpace";
46                 }
47
48                 wxMilliSleep(500);
49
50                 if ( !std_client->wsInitialize() ) {
51                         throw "Unable to initialize WebSocket";
52                 }
53         } catch (const char *err) {
54                 wxMessageBox(err, "Error!");
55
56                 return false;
57         }
58
59         std_client->Show(true);
60         SetTopWindow(std_client);
61
62         return true;
63 }
64
65 void StandaloneApp::OnEventLoopEnter(wxEventLoopBase *loop)
66 {
67         if ( loop->IsMain() ) {
68 /*              try {
69                         if ( !std_client->startFreeSpace() ) {
70                                 throw "Unable to start FreeSpace";
71                         }
72
73                         wxMilliSleep(500);
74
75                         if ( !std_client->wsInitialize() ) {
76                                 throw "Unable to initialize WebSocket";
77                         }
78                 } catch (const char *err) {
79                         wxMessageBox(err, "Error!");
80
81                 //      return false;
82                 }*/
83         }
84 }
85
86 StandaloneTimer::StandaloneTimer(Standalone *stand)
87 {
88         m_stand = stand;
89 }
90
91 StandaloneTimer::~StandaloneTimer()
92 {
93 }
94
95 void StandaloneTimer::Notify()
96 {
97         m_stand->wsDoFrame();
98 }
99
100 wxBEGIN_EVENT_TABLE(Standalone, wxDialog)
101         EVT_CLOSE(Standalone::OnClose)
102         EVT_BUTTON(ID_B_SHUTDOWN, Standalone::OnShutdown)
103 wxEND_EVENT_TABLE()
104
105 Standalone::Standalone( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
106 {
107         this->SetSizeHints( wxDefaultSize, wxDefaultSize );
108
109         fspid = 0;
110         fsport = DEFAULT_GAME_PORT;
111         stand_context = NULL;
112         wsi_standalone = NULL;
113         m_rate_limit = 0;
114
115         m_timer = new StandaloneTimer(this);
116         m_timer->Start(1000/30);
117
118         wxBoxSizer* bSizer1;
119         bSizer1 = new wxBoxSizer( wxVERTICAL );
120
121         wxNotebook* nbook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
122
123         createTab_Server(nbook);
124         createTab_Multi(nbook);
125         createTab_Player(nbook);
126         createTab_GodStuff(nbook);
127         createTab_Debug(nbook);
128
129         bSizer1->Add( nbook, 1, wxEXPAND | wxALL, 5 );
130
131         wxButton* bshutdown = new wxButton( this, ID_B_SHUTDOWN, wxT("Shutdown"), wxDefaultPosition, wxDefaultSize, 0 );
132         bSizer1->Add( bshutdown, 0, wxALIGN_CENTER|wxALL, 5 );
133
134
135         this->SetSizer( bSizer1 );
136         bSizer1->Fit(this);
137         bSizer1->SetSizeHints(this);
138
139         this->Centre( wxBOTH );
140 }
141
142 Standalone::~Standalone()
143 {
144         delete m_timer;
145 }
146
147 void Standalone::OnClose( wxCloseEvent& WXUNUSED(event) )
148 {
149         Shutdown();
150 }
151
152 void Standalone::OnShutdown( wxCommandEvent& WXUNUSED(event) )
153 {
154         Shutdown();
155 }
156
157 void Standalone::Shutdown()
158 {
159         if (stand_context) {
160                 std::string msg("shutdown");
161                 wsSend(msg);
162
163                 lws_service(stand_context, 50);
164
165                 lws_context_destroy(stand_context);
166         }
167
168         if ( wxProcess::Exists(fspid) ) {
169                 // wait a little bit, and if process still exists then kill it
170                 wxSleep(1);
171
172                 if ( wxProcess::Exists(fspid) ) {
173                         wxProcess::Kill(fspid, wxSIGTERM);
174                 }
175         }
176
177         Destroy();
178 }
179
180 void Standalone::createTab_Server(wxNotebook* parent)
181 {
182         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
183
184         wxBoxSizer *panelSizer = new wxBoxSizer( wxVERTICAL );
185
186         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
187
188         wxFlexGridSizer* fgSizer5 = new wxFlexGridSizer( 0, 2, 0, 0 );
189         fgSizer5->AddGrowableCol(1, 1);
190
191         wxStaticText* m_staticText6 = new wxStaticText( panel, wxID_ANY, wxT("Server Name"), wxDefaultPosition, wxDefaultSize, 0 );
192         fgSizer5->Add( m_staticText6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
193
194         m_S_ServerName = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
195         m_S_ServerName->SetMaxLength( 31 );
196         fgSizer5->Add( m_S_ServerName, 0, wxALL|wxEXPAND, 5 );
197
198         wxStaticText* m_staticText7 = new wxStaticText( panel, wxID_ANY, wxT("Host Password"), wxDefaultPosition, wxDefaultSize, 0 );
199         fgSizer5->Add( m_staticText7, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
200
201         m_S_HostPass = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
202         m_S_HostPass->SetMaxLength( 16 );
203         fgSizer5->Add( m_S_HostPass, 0, wxALL|wxEXPAND, 5 );
204
205         bSizer->Add( fgSizer5, 0, wxEXPAND, 0 );
206
207         wxStaticLine* m_staticline1 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
208         bSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 );
209
210         wxFlexGridSizer* fgSizer7 = new wxFlexGridSizer( 0, 2, 0, 0 );
211         fgSizer7->SetFlexibleDirection( wxBOTH );
212         fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
213
214         wxStaticText* m_staticText9 = new wxStaticText( panel, wxID_ANY, wxT("# Connections :"), wxDefaultPosition, wxDefaultSize, 0 );
215         fgSizer7->Add( m_staticText9, 0, wxALL, 5 );
216
217         m_S_NumConn = new wxStaticText( panel, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, 0|wxSUNKEN_BORDER );
218         fgSizer7->Add( m_S_NumConn, 0, wxALL, 5 );
219
220         bSizer->Add( fgSizer7, 0, wxEXPAND, 5 );
221
222         wxStaticText* m_staticText8 = new wxStaticText( panel, wxID_ANY, wxT("Address and Ping"), wxDefaultPosition, wxDefaultSize, 0 );
223         bSizer->Add( m_staticText8, 0, wxALL, 5 );
224
225         wxFlexGridSizer* fgSizer3 = new wxFlexGridSizer( 0, 2, 0, 0 );
226         fgSizer3->SetFlexibleDirection( wxBOTH );
227         fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
228
229         m_S_Connections = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 300,300 ), wxTE_MULTILINE|wxTE_READONLY );
230         fgSizer3->Add( m_S_Connections, 0, wxALL|wxEXPAND, 5 );
231
232         wxBoxSizer* bbSizer = new wxBoxSizer( wxVERTICAL );
233
234         m_S_btnKick = new wxButton( panel, ID_B_KICK, wxT("Kick"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
235         bbSizer->Add( m_S_btnKick, 1, wxALL, 5 );
236
237         m_S_btnMRefresh = new wxButton( panel, ID_B_MREFRESH, wxT(" Refresh\nMissions"), wxDefaultPosition, wxDefaultSize, 0 );
238         bbSizer->Add( m_S_btnMRefresh, 2, wxALL, 5 );
239
240         m_S_btnResetAll = new wxButton( panel, ID_B_RESET_ALL, wxT("Reset All"), wxDefaultPosition, wxDefaultSize, 0 );
241         bbSizer->Add( m_S_btnResetAll, 3, wxALL, 5 );
242
243         fgSizer3->Add( bbSizer, 1, wxEXPAND, 5 );
244
245         bSizer->Add( fgSizer3, 0, wxEXPAND, 5 );
246
247         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
248
249         panel->SetSizer( panelSizer );
250         panelSizer->Fit( panel );
251         panelSizer->SetSizeHints( panel );
252
253         parent->AddPage( panel, wxT("Server"), true );
254 }
255
256 void Standalone::createTab_Multi(wxNotebook* parent)
257 {
258         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
259
260         wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
261
262         wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);
263
264         m_M_sliderFPS = new wxSlider( panel, ID_FPS_SLIDER, 30, 15, 60, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL );
265         bSizer->Add( m_M_sliderFPS, 0, wxALL|wxEXPAND, 5 );
266
267         wxFlexGridSizer* fgSizer8;
268         fgSizer8 = new wxFlexGridSizer( 0, 5, 0, 0 );
269         fgSizer8->AddGrowableCol(2, 1);
270
271         wxStaticText* m_staticText71 = new wxStaticText( panel, wxID_ANY, wxT("Frame Cap : "), wxDefaultPosition, wxDefaultSize, 0 );
272         m_staticText71->Wrap( -1 );
273         fgSizer8->Add( m_staticText71, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
274
275         wxPanel* fpsPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
276         wxBoxSizer* fpsSizer = new wxBoxSizer(wxHORIZONTAL);
277         m_M_FPS = new wxStaticText( fpsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(60, -1), 0 );
278         m_M_FPS->Wrap( -1 );
279         fpsSizer->Add( m_M_FPS, 0, wxALL, 2 );
280         fpsPanel->SetSizer(fpsSizer);
281         fpsSizer->Fit(fpsPanel);
282         fgSizer8->Add(fpsPanel, 0, wxALL, 3);
283
284
285         fgSizer8->Add( 0, 0, 1, wxEXPAND );
286
287         wxStaticText* m_staticText81 = new wxStaticText( panel, wxID_ANY, wxT("Realized FPS : "), wxDefaultPosition, wxDefaultSize, 0 );
288         m_staticText81->Wrap( -1 );
289         fgSizer8->Add( m_staticText81, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
290
291         wxPanel*fpscapPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
292         wxBoxSizer* fpscapSizer = new wxBoxSizer(wxHORIZONTAL);
293         m_M_FPSRel = new wxStaticText( fpscapPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(60, -1), 0 );
294         m_M_FPSRel->Wrap( -1 );
295         fpscapSizer->Add( m_M_FPSRel, 0, wxALL, 2 );
296         fpscapPanel->SetSizer(fpscapSizer);
297         fpscapSizer->Fit(fpscapPanel);
298         fgSizer8->Add(fpscapPanel, 0, wxALL, 3);
299
300
301         bSizer->Add( fgSizer8, 0, wxEXPAND, 5 );
302
303         wxStaticLine* m_staticline2 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
304         bSizer->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 );
305
306
307         bSizer->Add( 0, 0, 0, wxALL, 20 );
308
309
310         wxFlexGridSizer* fgSizer9;
311         fgSizer9 = new wxFlexGridSizer( 0, 2, 0, 0 );
312         fgSizer9->SetFlexibleDirection( wxBOTH );
313         fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
314
315         wxStaticText* m_staticText91 = new wxStaticText( panel, wxID_ANY, wxT("Mission Name : "), wxDefaultPosition, wxDefaultSize, 0 );
316         m_staticText91->Wrap( -1 );
317         fgSizer9->Add( m_staticText91, 0, wxALL, 5 );
318
319         wxPanel* mnPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
320         wxBoxSizer* mnSizer = new wxBoxSizer(wxHORIZONTAL);
321         m_M_MissionName = new wxStaticText( mnPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
322         m_M_MissionName->Wrap( -1 );
323         mnSizer->Add( m_M_MissionName, 0, wxALL, 2 );
324         mnPanel->SetSizer(mnSizer);
325         mnSizer->Fit(mnPanel);
326         fgSizer9->Add(mnPanel, 0, wxALL, 3);
327
328         wxStaticText* m_staticText101 = new wxStaticText( panel, wxID_ANY, wxT("Mission Time : "), wxDefaultPosition, wxDefaultSize, 0 );
329         m_staticText101->Wrap( -1 );
330         fgSizer9->Add( m_staticText101, 0, wxALL, 5 );
331
332         wxPanel* mtPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
333         wxBoxSizer* mtSizer = new wxBoxSizer(wxHORIZONTAL);
334         m_M_MissionTime = new wxStaticText( mtPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
335         m_M_MissionTime->Wrap( -1 );
336         mtSizer->Add( m_M_MissionTime, 0, wxALL, 2 );
337         mtPanel->SetSizer(mtSizer);
338         mtSizer->Fit(mtPanel);
339         fgSizer9->Add(mtPanel, 0, wxALL, 3);
340
341
342         bSizer->Add( fgSizer9, 0, wxEXPAND, 5 );
343
344
345         bSizer->Add( 0, 0, 0, wxALL, 20 );
346
347         wxBoxSizer* bSizer3 = new wxBoxSizer(wxHORIZONTAL);
348
349         wxBoxSizer* bSizer4 = new wxBoxSizer(wxVERTICAL);
350
351         wxStaticText* m_staticText11 = new wxStaticText( panel, wxID_ANY, wxT("Mission Goals"), wxDefaultPosition, wxDefaultSize, 0 );
352         m_staticText11->Wrap( -1 );
353         bSizer4->Add( m_staticText11, 0, wxALL, 5 );
354
355         m_M_Goals = new wxTreeCtrl( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT );
356         bSizer4->Add( m_M_Goals, 1, wxALL|wxEXPAND, 5 );
357
358         bSizer3->Add(bSizer4, 1, wxEXPAND);
359
360         wxBoxSizer* bSizer5 = new wxBoxSizer(wxVERTICAL);
361
362         wxStaticText* m_staticText12 = new wxStaticText( panel, wxID_ANY, wxT("Netgame Information"), wxDefaultPosition, wxDefaultSize, 0 );
363         m_staticText12->Wrap( -1 );
364         bSizer5->Add( m_staticText12, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
365
366         wxFlexGridSizer* fgSizer11;
367         fgSizer11 = new wxFlexGridSizer( 0, 2, 0, 0 );
368         fgSizer11->AddGrowableRow(0, 1);
369         fgSizer11->AddGrowableRow(1, 1);
370         fgSizer11->AddGrowableRow(2, 1);
371         fgSizer11->AddGrowableRow(3, 1);
372
373         wxStaticText* m_staticText13 = new wxStaticText( panel, wxID_ANY, wxT("Max Players"), wxDefaultPosition, wxDefaultSize, 0 );
374         m_staticText13->Wrap( -1 );
375         fgSizer11->Add( m_staticText13, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
376
377         m_M_ngMaxPlayers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
378         m_M_ngMaxPlayers->Wrap( -1 );
379         fgSizer11->Add( m_M_ngMaxPlayers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
380
381         wxStaticText* m_staticText15 = new wxStaticText( panel, wxID_ANY, wxT("Max Observers"), wxDefaultPosition, wxDefaultSize, 0 );
382         m_staticText15->Wrap( -1 );
383         fgSizer11->Add( m_staticText15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
384
385         m_M_ngMaxObservers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
386         m_M_ngMaxObservers->Wrap( -1 );
387         fgSizer11->Add( m_M_ngMaxObservers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
388
389         wxStaticText* m_staticText17 = new wxStaticText( panel, wxID_ANY, wxT("Security"), wxDefaultPosition, wxDefaultSize, 0 );
390         m_staticText17->Wrap( -1 );
391         fgSizer11->Add( m_staticText17, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
392
393         m_M_ngSecurity = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
394         m_M_ngSecurity->Wrap( -1 );
395         fgSizer11->Add( m_M_ngSecurity, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
396
397         wxStaticText* m_staticText19 = new wxStaticText( panel, wxID_ANY, wxT("Respawns"), wxDefaultPosition, wxDefaultSize, 0 );
398         m_staticText19->Wrap( -1 );
399         fgSizer11->Add( m_staticText19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
400
401         m_M_ngRespawns = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
402         m_M_ngRespawns->Wrap( -1 );
403         fgSizer11->Add( m_M_ngRespawns, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
404
405         bSizer5->Add( fgSizer11, 1, wxEXPAND );
406
407         bSizer3->Add(bSizer5, 1, wxEXPAND);
408
409         bSizer->Add( bSizer3, 1, wxEXPAND, 5 );
410
411         panelSizer->Add(bSizer, 1, wxALL|wxEXPAND, 5);
412
413         panel->SetSizer( panelSizer );
414         panelSizer->Fit( panel );
415         panelSizer->SetSizeHints( panel );
416
417         parent->AddPage( panel, wxT("Multi-Player") );
418 }
419
420 void Standalone::createTab_Player(wxNotebook* parent)
421 {
422         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
423
424         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
425
426         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
427
428         wxBoxSizer* bSizer21;
429         bSizer21 = new wxBoxSizer( wxHORIZONTAL );
430
431         wxStaticText* m_staticText211 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
432         m_staticText211->Wrap( -1 );
433         bSizer21->Add( m_staticText211, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
434
435         wxArrayString m_choice11Choices;
436         m_P_Players = new wxChoice( panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), m_choice11Choices, 0 );
437         m_P_Players->SetSelection( 0 );
438         bSizer21->Add( m_P_Players, 0, wxALL, 5 );
439
440         bSizer->Add( bSizer21, 0, wxEXPAND );
441
442
443         wxStaticLine* m_staticline4 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
444         bSizer->Add( m_staticline4, 0, wxEXPAND | wxALL, 5 );
445
446         wxFlexGridSizer* fgSizer14;
447         fgSizer14 = new wxFlexGridSizer( 0, 2, 0, 0 );
448
449         wxStaticText* m_staticText26 = new wxStaticText( panel, wxID_ANY, wxT("Ship Type"), wxDefaultPosition, wxDefaultSize, 0 );
450         m_staticText26->Wrap( -1 );
451         fgSizer14->Add( m_staticText26, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
452
453         wxPanel* stPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
454         wxBoxSizer* stSizer = new wxBoxSizer(wxHORIZONTAL);
455         m_P_ShipType = new wxStaticText( stPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
456         m_P_ShipType->Wrap( -1 );
457         stSizer->Add(m_P_ShipType, 0, wxALL, 2);
458         stPanel->SetSizer(stSizer);
459         stSizer->Fit(stPanel);
460         fgSizer14->Add( stPanel, 0, wxALL, 5 );
461
462         wxStaticText* m_staticText28 = new wxStaticText( panel, wxID_ANY, wxT("Avg Ping"), wxDefaultPosition, wxDefaultSize, 0 );
463         m_staticText28->Wrap( -1 );
464         fgSizer14->Add( m_staticText28, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
465
466         wxPanel* apPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
467         wxBoxSizer* apSizer = new wxBoxSizer(wxHORIZONTAL);
468         m_P_AvgPing = new wxStaticText( apPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
469         m_P_AvgPing->Wrap( -1 );
470         apSizer->Add(m_P_AvgPing, 0, wxALL, 2);
471         apPanel->SetSizer(apSizer);
472         apSizer->Fit(apPanel);
473         fgSizer14->Add( apPanel, 0, wxALL, 5 );
474
475         bSizer->Add( fgSizer14, 0, wxEXPAND );
476
477         bSizer->Add( 0, 0, 0, wxALL, 10);
478
479         wxBoxSizer* bSizer6;
480         bSizer6 = new wxBoxSizer( wxHORIZONTAL );
481
482         //
483         // All-Time Stats
484         //
485
486         wxBoxSizer* atsboxSizer = new wxBoxSizer( wxVERTICAL );
487
488         wxStaticText* atsText = new wxStaticText( panel, wxID_ANY, wxT("All Time Stats") );
489         atsboxSizer->Add( atsText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
490
491         wxFlexGridSizer* atsgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
492         atsgSizer->AddGrowableCol(1, 1);
493
494         // primary shots
495         {
496                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
497                 itxt->Wrap( -1 );
498                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
499                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
500                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
501                 m_P_atsPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
502                 m_P_atsPriShots->Wrap( -1 );
503                 p1sizer->Add( m_P_atsPriShots, 1, wxALL|wxEXPAND, 1);
504                 p1->SetSizer( p1sizer );
505                 p1sizer->Fit( p1 );
506                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
507         }
508
509         // primary hits
510         {
511                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
512                 itxt->Wrap( -1 );
513                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
514                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
515                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
516                 m_P_atsPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
517                 m_P_atsPriHits->Wrap( -1 );
518                 p1sizer->Add( m_P_atsPriHits, 0, wxALL|wxEXPAND, 1);
519                 p1->SetSizer( p1sizer );
520                 p1sizer->Fit( p1 );
521                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
522         }
523
524         // primary BH hits
525         {
526                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
527                 itxt->Wrap( -1 );
528                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
529                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
530                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
531                 m_P_atsPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
532                 m_P_atsPriBHHits->Wrap( -1 );
533                 p1sizer->Add( m_P_atsPriBHHits, 0, wxALL|wxEXPAND, 1);
534                 p1->SetSizer( p1sizer );
535                 p1sizer->Fit( p1 );
536                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
537         }
538
539         // primary hit %
540         {
541                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
542                 itxt->Wrap( -1 );
543                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
544                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
545                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
546                 m_P_atsPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
547                 m_P_atsPriHitPer->Wrap( -1 );
548                 p1sizer->Add( m_P_atsPriHitPer, 0, wxALL|wxEXPAND, 1);
549                 p1->SetSizer( p1sizer );
550                 p1sizer->Fit( p1 );
551                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
552         }
553
554         // primary BH hit %
555         {
556                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
557                 itxt->Wrap( -1 );
558                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
559                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
560                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
561                 m_P_atsPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
562                 m_P_atsPriBHHitPer->Wrap( -1 );
563                 p1sizer->Add( m_P_atsPriBHHitPer, 0, wxALL|wxEXPAND, 1);
564                 p1->SetSizer( p1sizer );
565                 p1sizer->Fit( p1 );
566                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
567         }
568
569         // secondary shots
570         {
571                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
572                 itxt->Wrap( -1 );
573                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
574                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
575                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
576                 m_P_atsSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
577                 m_P_atsSecShots->Wrap( -1 );
578                 p1sizer->Add( m_P_atsSecShots, 0, wxALL|wxEXPAND, 1);
579                 p1->SetSizer( p1sizer );
580                 p1sizer->Fit( p1 );
581                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
582         }
583
584         // secondary hits
585         {
586                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
587                 itxt->Wrap( -1 );
588                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
589                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
590                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
591                 m_P_atsSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
592                 m_P_atsSecHits->Wrap( -1 );
593                 p1sizer->Add( m_P_atsSecHits, 0, wxALL|wxEXPAND, 1);
594                 p1->SetSizer( p1sizer );
595                 p1sizer->Fit( p1 );
596                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
597         }
598
599         // secondary BH hits
600         {
601                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
602                 itxt->Wrap( -1 );
603                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
604                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
605                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
606                 m_P_atsSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
607                 m_P_atsSecBHHits->Wrap( -1 );
608                 p1sizer->Add( m_P_atsSecBHHits, 0, wxALL|wxEXPAND, 1);
609                 p1->SetSizer( p1sizer );
610                 p1sizer->Fit( p1 );
611                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
612         }
613
614         // secondary hit %
615         {
616                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
617                 itxt->Wrap( -1 );
618                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
619                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
620                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
621                 m_P_atsSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
622                 m_P_atsSecHitPer->Wrap( -1 );
623                 p1sizer->Add( m_P_atsSecHitPer, 0, wxALL|wxEXPAND, 1);
624                 p1->SetSizer( p1sizer );
625                 p1sizer->Fit( p1 );
626                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
627         }
628
629         // secondary BH hit %
630         {
631                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
632                 itxt->Wrap( -1 );
633                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
634                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
635                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
636                 m_P_atsSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
637                 m_P_atsSecBHHitPer->Wrap( -1 );
638                 p1sizer->Add( m_P_atsSecBHHitPer, 0, wxALL|wxEXPAND, 1);
639                 p1->SetSizer( p1sizer );
640                 p1sizer->Fit( p1 );
641                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
642         }
643
644         // assists
645         {
646                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
647                 itxt->Wrap( -1 );
648                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
649                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
650                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
651                 m_P_atsAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
652                 m_P_atsAssists->Wrap( -1 );
653                 p1sizer->Add( m_P_atsAssists, 0, wxALL|wxEXPAND, 1);
654                 p1->SetSizer( p1sizer );
655                 p1sizer->Fit( p1 );
656                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
657         }
658
659         atsboxSizer->Add( atsgSizer, 1, wxEXPAND );
660
661         bSizer6->Add( atsboxSizer, 1, wxEXPAND, 5 );
662
663         wxStaticLine* m_staticline3 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
664         bSizer6->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 );
665
666         //
667         // Mission Stats
668         //
669
670         wxBoxSizer* msboxSizer = new wxBoxSizer( wxVERTICAL );
671
672         wxStaticText* msText = new wxStaticText( panel, wxID_ANY, wxT("Mission Stats") );
673         msboxSizer->Add( msText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
674
675         wxFlexGridSizer* msgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
676         msgSizer->AddGrowableCol(1, 1);
677
678         // primary shots
679         {
680                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
681                 itxt->Wrap( -1 );
682                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
683                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
684                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
685                 m_P_msPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
686                 m_P_msPriShots->Wrap( -1 );
687                 p1sizer->Add( m_P_msPriShots, 1, wxALL|wxEXPAND, 1);
688                 p1->SetSizer( p1sizer );
689                 p1sizer->Fit( p1 );
690                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
691         }
692
693         // primary hits
694         {
695                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
696                 itxt->Wrap( -1 );
697                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
698                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
699                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
700                 m_P_msPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
701                 m_P_msPriHits->Wrap( -1 );
702                 p1sizer->Add( m_P_msPriHits, 0, wxALL|wxEXPAND, 1);
703                 p1->SetSizer( p1sizer );
704                 p1sizer->Fit( p1 );
705                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
706         }
707
708         // primary BH hits
709         {
710                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
711                 itxt->Wrap( -1 );
712                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
713                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
714                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
715                 m_P_msPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
716                 m_P_msPriBHHits->Wrap( -1 );
717                 p1sizer->Add( m_P_msPriBHHits, 0, wxALL|wxEXPAND, 1);
718                 p1->SetSizer( p1sizer );
719                 p1sizer->Fit( p1 );
720                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
721         }
722
723         // primary hit %
724         {
725                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
726                 itxt->Wrap( -1 );
727                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
728                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
729                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
730                 m_P_msPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
731                 m_P_msPriHitPer->Wrap( -1 );
732                 p1sizer->Add( m_P_msPriHitPer, 0, wxALL|wxEXPAND, 1);
733                 p1->SetSizer( p1sizer );
734                 p1sizer->Fit( p1 );
735                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
736         }
737
738         // primary BH hit %
739         {
740                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
741                 itxt->Wrap( -1 );
742                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
743                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
744                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
745                 m_P_msPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
746                 m_P_msPriBHHitPer->Wrap( -1 );
747                 p1sizer->Add( m_P_msPriBHHitPer, 0, wxALL|wxEXPAND, 1);
748                 p1->SetSizer( p1sizer );
749                 p1sizer->Fit( p1 );
750                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
751         }
752
753         // secondary shots
754         {
755                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
756                 itxt->Wrap( -1 );
757                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
758                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
759                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
760                 m_P_msSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
761                 m_P_msSecShots->Wrap( -1 );
762                 p1sizer->Add( m_P_msSecShots, 0, wxALL|wxEXPAND, 1);
763                 p1->SetSizer( p1sizer );
764                 p1sizer->Fit( p1 );
765                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
766         }
767
768         // secondary hits
769         {
770                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
771                 itxt->Wrap( -1 );
772                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
773                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
774                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
775                 m_P_msSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
776                 m_P_msSecHits->Wrap( -1 );
777                 p1sizer->Add( m_P_msSecHits, 0, wxALL|wxEXPAND, 1);
778                 p1->SetSizer( p1sizer );
779                 p1sizer->Fit( p1 );
780                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
781         }
782
783         // secondary BH hits
784         {
785                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
786                 itxt->Wrap( -1 );
787                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
788                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
789                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
790                 m_P_msSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
791                 m_P_msSecBHHits->Wrap( -1 );
792                 p1sizer->Add( m_P_msSecBHHits, 0, wxALL|wxEXPAND, 1);
793                 p1->SetSizer( p1sizer );
794                 p1sizer->Fit( p1 );
795                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
796         }
797
798         // secondary hit %
799         {
800                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
801                 itxt->Wrap( -1 );
802                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
803                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
804                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
805                 m_P_msSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
806                 m_P_msSecHitPer->Wrap( -1 );
807                 p1sizer->Add( m_P_msSecHitPer, 0, wxALL|wxEXPAND, 1);
808                 p1->SetSizer( p1sizer );
809                 p1sizer->Fit( p1 );
810                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
811         }
812
813         // secondary BH hit %
814         {
815                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
816                 itxt->Wrap( -1 );
817                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
818                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
819                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
820                 m_P_msSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
821                 m_P_msSecBHHitPer->Wrap( -1 );
822                 p1sizer->Add( m_P_msSecBHHitPer, 0, wxALL|wxEXPAND, 1);
823                 p1->SetSizer( p1sizer );
824                 p1sizer->Fit( p1 );
825                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
826         }
827
828         // assists
829         {
830                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
831                 itxt->Wrap( -1 );
832                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
833                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
834                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
835                 m_P_msAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
836                 m_P_msAssists->Wrap( -1 );
837                 p1sizer->Add( m_P_msAssists, 0, wxALL|wxEXPAND, 1);
838                 p1->SetSizer( p1sizer );
839                 p1sizer->Fit( p1 );
840                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
841         }
842
843         msboxSizer->Add( msgSizer, 1, wxEXPAND );
844
845         bSizer6->Add( msboxSizer, 1, wxEXPAND );
846
847         bSizer->Add( bSizer6, 1, wxEXPAND );
848
849         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
850
851         panel->SetSizer( panelSizer );
852         panelSizer->Fit( panel );
853         panelSizer->SetSizeHints(panel);
854
855         parent->AddPage( panel, wxT("Player Info") );
856 }
857
858 void Standalone::createTab_GodStuff(wxNotebook* parent)
859 {
860         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
861
862         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
863
864         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
865
866         wxBoxSizer* bSizer2 = new wxBoxSizer( wxHORIZONTAL );
867
868         wxStaticText* m_staticText21 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
869         bSizer2->Add( m_staticText21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
870
871         wxArrayString m_choice1Choices;
872         m_GS_Players = new wxChoice( panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), m_choice1Choices, 0 );
873         m_GS_Players->SetSelection( 0 );
874         bSizer2->Add( m_GS_Players, 0, wxALL|wxEXPAND, 5 );
875
876         bSizer->Add( bSizer2, 0, wxEXPAND, 5 );
877
878         bSizer->Add( 0, 0, 0, wxALL, 10 );
879
880         wxStaticText* m_staticText22 = new wxStaticText( panel, wxID_ANY, wxT("Server Message"), wxDefaultPosition, wxDefaultSize, 0 );
881         bSizer->Add( m_staticText22, 0, wxALL, 5 );
882
883         wxTextCtrl* m_textCtrl9 = new wxTextCtrl( panel, ID_T_MSG, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
884         bSizer->Add( m_textCtrl9, 0, wxALL|wxEXPAND, 5 );
885
886         bSizer->Add( 0, 0, 0, wxALL, 5 );
887
888         m_GS_Messages = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY );
889         bSizer->Add( m_GS_Messages, 1, wxALL|wxEXPAND, 5 );
890
891         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
892
893         panel->SetSizer( panelSizer );
894         panelSizer->Fit( panel );
895         panelSizer->SetSizeHints( panel );
896
897         parent->AddPage( panel, wxT("God Stuff") );
898 }
899
900 void Standalone::createTab_Debug(wxNotebook* parent)
901 {
902         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
903
904         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
905
906         wxBoxSizer* hbSizer = new wxBoxSizer( wxHORIZONTAL );
907
908         wxStaticText* m_staticText1 = new wxStaticText( panel, wxID_ANY, wxT("Standalone State :"), wxDefaultPosition, wxDefaultSize, 0 );
909         hbSizer->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
910
911         wxPanel* p1 = new wxPanel( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER );
912
913         wxBoxSizer* p1Sizer = new wxBoxSizer( wxHORIZONTAL );
914
915         m_D_State = new wxStaticText( p1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
916         p1Sizer->Add( m_D_State, 1, wxALL|wxEXPAND, 2);
917
918         p1->SetSizer( p1Sizer );
919         p1Sizer->Fit( p1 );
920
921         hbSizer->Add( p1, 1, wxALL|wxEXPAND, 5 );
922
923         bSizer->Add( hbSizer, 0, wxALL|wxEXPAND, 5 );
924
925         panel->SetSizer( bSizer );
926         panel->Layout();
927
928         bSizer->Fit( panel );
929
930         parent->AddPage( panel, wxT("Debug") );
931 }
932
933 bool Standalone::startFreeSpace()
934 {
935         wxString epath = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(true);
936
937 #ifdef MAKE_FS1
938         epath.Append( wxT("freespace") );
939 #else
940         epath.Append( wxT("freespace2") );
941 #endif
942
943 #ifdef FS2_DEMO
944         epath.Append( wxT("_demo") );
945 #endif
946
947 #ifdef _WIN32
948         epath.Append( wxT(".exe") );
949 #endif
950
951         epath.Append( wxT(" -standalone") );
952 /*
953         for (int i = 1; i < wxApp().argc; i++) {
954                 wxString arg( wxApp().argv[i] );
955
956                 // check if -port argument and set var
957                 if ( arg.IsSameAs( wxT("-port"), false) && (wxApp().argc > i+1) ) {
958                         fsport = wxAtoi(wxApp().argv[i+1]);
959                 }
960
961                 epath.Append( wxT(" ") );
962                 epath.Append(arg);
963         }
964 */
965         fspid = wxExecute(epath, wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER | wxEXEC_HIDE_CONSOLE);
966
967         return (fspid > 0);
968 }
969
970 static int callback_standalone_client(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
971 {
972         #define MAX_BUF_SIZE    1050
973         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BUF_SIZE + LWS_SEND_BUFFER_POST_PADDING];
974         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
975         int rval;
976         int size;
977
978         switch (reason) {
979                 case LWS_CALLBACK_CLIENT_ESTABLISHED:
980                         lwsl_notice("CLIENT_ESTABLISHED\n");
981                         lws_callback_on_writable(wsi);
982                         break;
983
984                 case LWS_CALLBACK_CLOSED:
985                         lwsl_notice("CLOSED\n");
986                         wxGetApp().Client().wsDisconnect();
987                         break;
988
989                 case LWS_CALLBACK_CLIENT_RECEIVE:
990                         lwsl_notice("CLIENT_RECEIVE => in: %s, len: %lu\n", in ? (char*)in : "nul", len);
991                         wxGetApp().Client().wsMessage( (const char *)in, len );
992                         break;
993
994                 case LWS_CALLBACK_CLIENT_WRITEABLE: {
995                         lwsl_notice("CLIENT_WRITEABLE\n");
996                         if ( !wxGetApp().Client().wsGetSendBuffer().empty() ) {
997                                 std::string msg = wxGetApp().Client().wsGetSendBuffer().front();
998
999                                 size = wxStrlcpy((char *)p, msg.c_str(), MAX_BUF_SIZE);
1000
1001                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
1002
1003                                 if (rval < size) {
1004                                         lwsl_err("ERROR sending buffer!\n");
1005                                         return -1;
1006                                 }
1007
1008                                 wxGetApp().Client().wsGetSendBuffer().pop_front();
1009
1010                                 lws_callback_on_writable(wsi);
1011                         }
1012
1013                         break;
1014                 }
1015
1016                 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
1017                         lwsl_notice("CONNECTION_ERROR\n");
1018                         wxGetApp().Client().wsDisconnect();
1019                         break;
1020
1021                 default:
1022                         break;
1023         }
1024
1025         return 0;
1026 }
1027
1028 static struct lws_protocols protocols[] = {
1029         {
1030                 "standalone",
1031                 callback_standalone_client,
1032                 0,
1033                 0
1034         },
1035         { NULL, NULL, 0, 0 }
1036 };
1037
1038 bool Standalone::wsInitialize()
1039 {
1040         struct lws_context_creation_info info;
1041
1042         memset(&info, 0, sizeof(info));
1043         memset(&ccinfo, 0, sizeof(ccinfo));
1044
1045         info.port = CONTEXT_PORT_NO_LISTEN;
1046         info.protocols = protocols;
1047         info.gid = -1;
1048         info.uid = -1;
1049
1050         stand_context = lws_create_context(&info);
1051
1052         if (stand_context == NULL) {
1053                 return false;
1054         }
1055
1056         ccinfo.context = stand_context;
1057         ccinfo.address = "127.0.0.1";
1058         ccinfo.port = fsport;
1059         ccinfo.path = "/";
1060         ccinfo.host = ccinfo.address;
1061         ccinfo.origin = ccinfo.address;
1062         ccinfo.ietf_version_or_minus_one = -1;
1063         ccinfo.protocol = protocols[0].name;
1064
1065         // async call, actual connection to occur later
1066         wsi_standalone = lws_client_connect_via_info(&ccinfo);
1067
1068         lws_service(stand_context, 0);
1069
1070         return true;
1071 }
1072
1073 void Standalone::wsDoFrame()
1074 {
1075         if ( !stand_context ) {
1076                 return;
1077         }
1078
1079         // if connection is lost attempt reconnect every 2 seconds
1080         if ( !wsi_standalone && !(++m_rate_limit % 60) ) {
1081                 wsi_standalone = lws_client_connect_via_info(&ccinfo);
1082                 m_rate_limit = 0;
1083         }
1084
1085         lws_service(stand_context, 0);
1086 }
1087
1088 void Standalone::wsDisconnect()
1089 {
1090         lwsl_notice("disconnect!\n");
1091         wsi_standalone = NULL;
1092 }
1093
1094 void Standalone::wsMessage(const char *msg, size_t len)
1095 {
1096         if (msg == NULL || len < 5) {
1097                 return;
1098         }
1099
1100         char mtype = msg[0];
1101
1102         if (mtype == 'T') {
1103                 SetTitle(msg+2);
1104         } else if (mtype == 'D') {
1105                 m_D_State->SetLabel(msg+2);
1106         }
1107         // server tab
1108         else if (mtype == 'S') {
1109                 wxString cmd(msg+2, 4);
1110
1111                 if (cmd == "name") {
1112                         m_S_ServerName->SetValue(msg+7);
1113                 } else if (cmd == "pass") {
1114                         m_S_HostPass->SetValue(msg+7);
1115                 } else if (cmd == "conn") {
1116
1117                 } else if (cmd == "ping") {
1118
1119                 }
1120         }
1121         // multi-player tab
1122         else if (mtype == 'M') {
1123                 wxString cmd(msg+2, 4);
1124
1125                 if (cmd == "name") {
1126                         m_M_MissionName->SetLabel(msg+7);
1127                 } else if (cmd == "time") {
1128                         m_M_MissionTime->SetLabel(msg+7);
1129                 } else if (cmd == "info") {
1130                         wxArrayString ng_info = wxSplit(msg+7, ',');
1131
1132                         m_M_ngMaxPlayers->SetLabel( ng_info.Item(0) );
1133                         m_M_ngMaxObservers->SetLabel( ng_info.Item(1) );
1134                         m_M_ngSecurity->SetLabel( ng_info.Item(2) );
1135                         m_M_ngRespawns->SetLabel( ng_info.Item(3) );
1136                 } else if (cmd == "fps ") {
1137                         m_M_FPSRel->SetLabel(msg+6);
1138                 } else if (cmd == "goal") {
1139
1140                 }
1141         }
1142         // player tab
1143         else if (mtype == 'P') {
1144                 wxString cmd(msg+2, 4);
1145
1146                 if (cmd == "info") {
1147
1148                 }
1149         }
1150         // god stuff tab
1151         else if (mtype == 'G') {
1152                 wxString cmd(msg+2, 4);
1153
1154                 if (cmd == "mesg") {
1155                         m_GS_Messages->AppendText(msg+7);
1156                 }
1157         }
1158 }
1159
1160 void Standalone::wsSend(std::string &msg)
1161 {
1162         send_buf.push_back(msg);
1163
1164         if (wsi_standalone) {
1165                 lws_callback_on_writable(wsi_standalone);
1166         }
1167 }