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