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