]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/stand_gui.cpp
clean up Windows #include's and use winsock2
[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 #include "stand_gui.h"
11 #include "osregistry.h"
12
13 #include "wx/statline.h"
14 #include "wx/filename.h"
15 #include "wx/stdpaths.h"
16 #include "wx/utils.h"
17 #include "wx/msgdlg.h"
18 #include "wx/process.h"
19 #include "wx/textfile.h"
20 #include "wx/socket.h"
21
22 #include "SDL.h"
23
24
25 // taken from psnet.h and psnet2.h
26 #ifdef MAKE_FS1
27         #define DEFAULT_GAME_PORT 4000
28 #elif defined(FS2_DEMO)
29         #define DEFAULT_GAME_PORT 7802
30 #else
31         #define DEFAULT_GAME_PORT 7808
32 #endif
33
34 // taken from osregistry.cpp
35 const char *Osreg_company_name = "Volition";
36 #if defined(FS1_DEMO)
37 const char *Osreg_title = "FreeSpace Demo";
38 #define PROFILE_NAME "FreeSpaceDemo.ini"
39 #elif defined(FS2_DEMO)
40 const char *Osreg_title = "FreeSpace 2 Demo";
41 #define PROFILE_NAME "FreeSpace2Demo.ini"
42 #elif defined(OEM_BUILD)
43 const char *Osreg_title = "FreeSpace 2 OEM";
44 #define PROFILE_NAME "FreeSpace2OEM.ini"
45 #elif defined(MAKE_FS1)
46 const char *Osreg_title = "FreeSpace";
47 #define PROFILE_NAME "FreeSpace.ini"
48 #else
49 const char *Osreg_title = "FreeSpace 2";
50 #define PROFILE_NAME "FreeSpace2.ini"
51 #endif
52
53
54 IMPLEMENT_APP(StandaloneApp)
55
56 bool StandaloneApp::OnInit()
57 {
58         if ( !wxApp::OnInit() ) {
59                 return false;
60         }
61
62         std_client = new Standalone(NULL);
63
64         try {
65                 if ( !std_client->startFreeSpace(argc, argv) ) {
66                         throw "Unable to start FreeSpace";
67                 }
68
69                 wxMilliSleep(500);
70
71                 if ( !std_client->wsInitialize() ) {
72                         throw "Unable to initialize WebSocket";
73                 }
74         } catch (const char *err) {
75                 wxMessageBox(err, "Error!", wxOK|wxICON_ERROR|wxCENTRE|wxSTAY_ON_TOP);
76
77                 return false;
78         }
79
80         std_client->Show(true);
81         SetTopWindow(std_client);
82
83         return true;
84 }
85
86 StandaloneTimer::StandaloneTimer(Standalone *stand)
87 {
88         m_stand = stand;
89 }
90
91 StandaloneTimer::~StandaloneTimer()
92 {
93 }
94
95 void StandaloneTimer::Notify()
96 {
97         m_stand->wsDoFrame();
98 }
99
100 StandPopup::StandPopup( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
101 {
102         this->SetSizeHints( wxSize( 350,100 ), wxDefaultSize );
103
104         wxBoxSizer* bSizer2;
105         bSizer2 = new wxBoxSizer( wxVERTICAL );
106
107         wxFlexGridSizer* fgSizer3;
108         fgSizer3 = new wxFlexGridSizer( 0, 2, 0, 0 );
109         fgSizer3->AddGrowableRow(0, 1);
110
111         m_Label1 = new wxStaticText( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
112         m_Label1->Wrap( -1 );
113         fgSizer3->Add( m_Label1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
114
115         m_Label2 = new wxStaticText( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
116         m_Label2->Wrap( -1 );
117         fgSizer3->Add( m_Label2, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
118
119
120         bSizer2->Add( fgSizer3, 1, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 10 );
121
122
123         this->SetSizer( bSizer2 );
124         this->Layout();
125         bSizer2->Fit( this );
126
127         this->Centre( wxBOTH );
128 }
129
130 StandPopup::~StandPopup()
131 {
132 }
133
134 wxBEGIN_EVENT_TABLE(Standalone, wxDialog)
135         EVT_CLOSE(Standalone::OnClose)
136         EVT_BUTTON(ID_B_SHUTDOWN, Standalone::OnShutdown)
137         EVT_BUTTON(ID_B_KICK, Standalone::OnKick)
138         EVT_BUTTON(ID_B_MREFRESH, Standalone::OnMissionRefresh)
139         EVT_BUTTON(ID_B_RESET_ALL, Standalone::OnResetAll)
140         EVT_SLIDER(ID_FPS_SLIDER, Standalone::OnFPSSel)
141         EVT_TEXT_ENTER(ID_T_MSG, Standalone::OnServerMsg)
142         EVT_TEXT_ENTER(ID_T_SERVER_NAME, Standalone::OnServerNameChange)
143         EVT_TEXT_ENTER(ID_T_HOST_PASS, Standalone::OnHostPassChange)
144         EVT_CHOICE(ID_C_P_PLAYERS, Standalone::OnPinfoPlayer)
145 wxEND_EVENT_TABLE()
146
147 Standalone::Standalone( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
148 {
149         this->SetSizeHints( wxDefaultSize, wxDefaultSize );
150
151         fspid = 0;
152         fsport = DEFAULT_GAME_PORT;
153         stand_context = NULL;
154         wsi_standalone = NULL;
155         m_rate_limit = 0;
156
157         m_timer = new StandaloneTimer(this);
158         m_timer->Start(1000/30);
159
160         m_popup = new StandPopup(this);
161         m_popup->Show(false);
162
163         wxBoxSizer* bSizer1;
164         bSizer1 = new wxBoxSizer( wxVERTICAL );
165
166         wxNotebook* nbook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
167
168         createTab_Server(nbook);
169         createTab_Multi(nbook);
170         createTab_Player(nbook);
171         createTab_GodStuff(nbook);
172         createTab_Debug(nbook);
173
174         bSizer1->Add( nbook, 1, wxEXPAND | wxALL, 5 );
175
176         wxButton* bshutdown = new wxButton( this, ID_B_SHUTDOWN, wxT("Shutdown"), wxDefaultPosition, wxDefaultSize, 0 );
177         bSizer1->Add( bshutdown, 0, wxALIGN_CENTER|wxALL, 5 );
178
179
180         this->SetSizer( bSizer1 );
181         bSizer1->Fit(this);
182         bSizer1->SetSizeHints(this);
183
184         this->Centre( wxBOTH );
185 }
186
187 Standalone::~Standalone()
188 {
189         delete m_timer;
190 }
191
192 void Standalone::OnClose( wxCloseEvent& WXUNUSED(event) )
193 {
194         Shutdown();
195 }
196
197 void Standalone::OnShutdown( wxCommandEvent& WXUNUSED(event) )
198 {
199         Shutdown();
200 }
201
202 void Standalone::Shutdown()
203 {
204         if (stand_context) {
205                 std::string msg("shutdown");
206                 wsSend(msg);
207
208                 lws_service(stand_context, 50);
209
210                 lws_context_destroy(stand_context);
211         }
212
213         if ( wxProcess::Exists(fspid) ) {
214                 // wait a little bit, and if process still exists then kill it
215                 wxSleep(1);
216
217                 if ( wxProcess::Exists(fspid) ) {
218                         wxProcess::Kill(fspid, wxSIGTERM);
219                 }
220         }
221
222         Destroy();
223 }
224
225 void Standalone::OnServerNameChange(wxCommandEvent& WXUNUSED(event) )
226 {
227         std::string msg("S:name ");
228
229         msg.append( m_S_ServerName->GetValue().c_str() );
230
231         wsSend(msg);
232 }
233
234 void Standalone::OnHostPassChange(wxCommandEvent& WXUNUSED(event) )
235 {
236         std::string msg("S:pass ");
237
238         msg.append( m_S_HostPass->GetValue().c_str() );
239
240         wsSend(msg);
241 }
242
243 void Standalone::OnKick( wxCommandEvent& WXUNUSED(event) )
244 {
245         std::string msg("S:kick ");
246
247         long col, row;
248
249         if ( !m_S_Connections->PositionToXY(m_S_Connections->GetInsertionPoint(), &col, &row) ) {
250                 return;
251         }
252
253         wxString line = m_S_Connections->GetLineText(row);
254
255         if ( line.IsEmpty() ) {
256                 return;
257         }
258
259         wxArrayString ipaddr = wxSplit(line, ',');
260
261         msg.append( ipaddr.Item(0).c_str() );
262
263         wsSend(msg);
264 }
265
266 void Standalone::OnMissionRefresh( wxCommandEvent& WXUNUSED(event) )
267 {
268         std::string msg("G:mrefresh");
269
270         wsSend(msg);
271 }
272
273 void Standalone::OnResetAll( wxCommandEvent& WXUNUSED(event) )
274 {
275         std::string msg("reset");
276
277         wsSend(msg);
278 }
279
280 void Standalone::OnFPSSel( wxCommandEvent& WXUNUSED(event) )
281 {
282         wxString fps = wxString::Format("%d", m_M_sliderFPS->GetValue());
283
284         m_M_FPS->SetLabel(fps);
285
286         std::string msg("M:fps ");
287         msg.append(fps);
288
289         wsSend(msg);
290 }
291
292 void Standalone::OnServerMsg( wxCommandEvent& WXUNUSED(event) )
293 {
294         if ( m_GS_msg->GetValue().IsEmpty() ) {
295                 return;
296         }
297
298         std::string msg("G:smsg ");
299
300         msg.append( m_GS_msg->GetValue().c_str() );
301
302         // strip off return char which GetValue() has
303         size_t pos = msg.find_last_not_of("\r\n");
304
305         if (pos != std::string::npos) {
306                 msg.erase(pos+1);
307         }
308
309         wsSend(msg);
310
311         m_GS_msg->Clear();
312 }
313
314 void Standalone::OnPinfoPlayer(wxCommandEvent& WXUNUSED(event) )
315 {
316         int idx = m_P_Players->GetCurrentSelection();
317
318         if (idx == wxNOT_FOUND) {
319                 return;
320         }
321
322         std::string msg("P:info ");
323
324         msg.append( m_P_Players->GetString(idx).c_str() );
325
326         wsSend(msg);
327 }
328
329 void Standalone::createTab_Server(wxNotebook* parent)
330 {
331         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
332
333         wxBoxSizer *panelSizer = new wxBoxSizer( wxVERTICAL );
334
335         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
336
337         wxFlexGridSizer* fgSizer5 = new wxFlexGridSizer( 0, 2, 0, 0 );
338         fgSizer5->AddGrowableCol(1, 1);
339
340         wxStaticText* m_staticText6 = new wxStaticText( panel, wxID_ANY, wxT("Server Name"), wxDefaultPosition, wxDefaultSize, 0 );
341         fgSizer5->Add( m_staticText6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
342
343         m_S_ServerName = new wxTextCtrl( panel, ID_T_SERVER_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
344         m_S_ServerName->SetMaxLength( 31 );
345         fgSizer5->Add( m_S_ServerName, 0, wxALL|wxEXPAND, 5 );
346
347         wxStaticText* m_staticText7 = new wxStaticText( panel, wxID_ANY, wxT("Host Password"), wxDefaultPosition, wxDefaultSize, 0 );
348         fgSizer5->Add( m_staticText7, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
349
350         m_S_HostPass = new wxTextCtrl( panel, ID_T_HOST_PASS, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
351         m_S_HostPass->SetMaxLength( 16 );
352         fgSizer5->Add( m_S_HostPass, 0, wxALL|wxEXPAND, 5 );
353
354         bSizer->Add( fgSizer5, 0, wxEXPAND, 0 );
355
356         wxStaticLine* m_staticline1 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
357         bSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 );
358
359         wxFlexGridSizer* fgSizer7 = new wxFlexGridSizer( 0, 2, 0, 0 );
360         fgSizer7->SetFlexibleDirection( wxBOTH );
361         fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
362
363         wxStaticText* m_staticText9 = new wxStaticText( panel, wxID_ANY, wxT("# Connections :"), wxDefaultPosition, wxDefaultSize, 0 );
364         fgSizer7->Add( m_staticText9, 0, wxALL, 5 );
365
366         m_S_NumConn = new wxStaticText( panel, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, 0|wxSUNKEN_BORDER );
367         fgSizer7->Add( m_S_NumConn, 0, wxALL, 5 );
368
369         bSizer->Add( fgSizer7, 0, wxEXPAND, 5 );
370
371         wxStaticText* m_staticText8 = new wxStaticText( panel, wxID_ANY, wxT("Address and Ping"), wxDefaultPosition, wxDefaultSize, 0 );
372         bSizer->Add( m_staticText8, 0, wxALL, 5 );
373
374         wxFlexGridSizer* fgSizer3 = new wxFlexGridSizer( 0, 2, 0, 0 );
375         fgSizer3->SetFlexibleDirection( wxBOTH );
376         fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
377
378         m_S_Connections = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 300,300 ), wxTE_MULTILINE|wxTE_READONLY );
379         fgSizer3->Add( m_S_Connections, 0, wxALL|wxEXPAND, 5 );
380
381         wxBoxSizer* bbSizer = new wxBoxSizer( wxVERTICAL );
382
383         m_S_btnKick = new wxButton( panel, ID_B_KICK, wxT("Kick"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
384         bbSizer->Add( m_S_btnKick, 1, wxALL, 5 );
385
386         m_S_btnMRefresh = new wxButton( panel, ID_B_MREFRESH, wxT(" Refresh\nMissions"), wxDefaultPosition, wxDefaultSize, 0 );
387         bbSizer->Add( m_S_btnMRefresh, 2, wxALL, 5 );
388
389         m_S_btnResetAll = new wxButton( panel, ID_B_RESET_ALL, wxT("Reset All"), wxDefaultPosition, wxDefaultSize, 0 );
390         bbSizer->Add( m_S_btnResetAll, 3, wxALL, 5 );
391
392         fgSizer3->Add( bbSizer, 1, wxEXPAND, 5 );
393
394         bSizer->Add( fgSizer3, 0, wxEXPAND, 5 );
395
396         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
397
398         panel->SetSizer( panelSizer );
399         panelSizer->Fit( panel );
400         panelSizer->SetSizeHints( panel );
401
402         parent->AddPage( panel, wxT("Server"), true );
403 }
404
405 void Standalone::createTab_Multi(wxNotebook* parent)
406 {
407         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
408
409         wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
410
411         wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);
412
413         m_M_sliderFPS = new wxSlider( panel, ID_FPS_SLIDER, 30, 15, 60, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL );
414         bSizer->Add( m_M_sliderFPS, 0, wxALL|wxEXPAND, 5 );
415
416         wxFlexGridSizer* fgSizer8;
417         fgSizer8 = new wxFlexGridSizer( 0, 5, 0, 0 );
418         fgSizer8->AddGrowableCol(2, 1);
419
420         wxStaticText* m_staticText71 = new wxStaticText( panel, wxID_ANY, wxT("Frame Cap : "), wxDefaultPosition, wxDefaultSize, 0 );
421         m_staticText71->Wrap( -1 );
422         fgSizer8->Add( m_staticText71, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
423
424         wxPanel* fpsPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
425         wxBoxSizer* fpsSizer = new wxBoxSizer(wxHORIZONTAL);
426         m_M_FPS = new wxStaticText( fpsPanel, wxID_ANY, "30", wxDefaultPosition, wxSize(60, -1), 0 );
427         m_M_FPS->Wrap( -1 );
428         fpsSizer->Add( m_M_FPS, 0, wxALL, 2 );
429         fpsPanel->SetSizer(fpsSizer);
430         fpsSizer->Fit(fpsPanel);
431         fgSizer8->Add(fpsPanel, 0, wxALL, 3);
432
433
434         fgSizer8->Add( 0, 0, 1, wxEXPAND );
435
436         wxStaticText* m_staticText81 = new wxStaticText( panel, wxID_ANY, wxT("Realized FPS : "), wxDefaultPosition, wxDefaultSize, 0 );
437         m_staticText81->Wrap( -1 );
438         fgSizer8->Add( m_staticText81, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
439
440         wxPanel*fpscapPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
441         wxBoxSizer* fpscapSizer = new wxBoxSizer(wxHORIZONTAL);
442         m_M_FPSRel = new wxStaticText( fpscapPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(60, -1), 0 );
443         m_M_FPSRel->Wrap( -1 );
444         fpscapSizer->Add( m_M_FPSRel, 0, wxALL, 2 );
445         fpscapPanel->SetSizer(fpscapSizer);
446         fpscapSizer->Fit(fpscapPanel);
447         fgSizer8->Add(fpscapPanel, 0, wxALL, 3);
448
449
450         bSizer->Add( fgSizer8, 0, wxEXPAND, 5 );
451
452         wxStaticLine* m_staticline2 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
453         bSizer->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 );
454
455
456         bSizer->Add( 0, 0, 0, wxALL, 20 );
457
458
459         wxFlexGridSizer* fgSizer9;
460         fgSizer9 = new wxFlexGridSizer( 0, 2, 0, 0 );
461         fgSizer9->SetFlexibleDirection( wxBOTH );
462         fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
463
464         wxStaticText* m_staticText91 = new wxStaticText( panel, wxID_ANY, wxT("Mission Name : "), wxDefaultPosition, wxDefaultSize, 0 );
465         m_staticText91->Wrap( -1 );
466         fgSizer9->Add( m_staticText91, 0, wxALL, 5 );
467
468         wxPanel* mnPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
469         wxBoxSizer* mnSizer = new wxBoxSizer(wxHORIZONTAL);
470         m_M_MissionName = new wxStaticText( mnPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
471         m_M_MissionName->Wrap( -1 );
472         mnSizer->Add( m_M_MissionName, 0, wxALL, 2 );
473         mnPanel->SetSizer(mnSizer);
474         mnSizer->Fit(mnPanel);
475         fgSizer9->Add(mnPanel, 0, wxALL, 3);
476
477         wxStaticText* m_staticText101 = new wxStaticText( panel, wxID_ANY, wxT("Mission Time : "), wxDefaultPosition, wxDefaultSize, 0 );
478         m_staticText101->Wrap( -1 );
479         fgSizer9->Add( m_staticText101, 0, wxALL, 5 );
480
481         wxPanel* mtPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
482         wxBoxSizer* mtSizer = new wxBoxSizer(wxHORIZONTAL);
483         m_M_MissionTime = new wxStaticText( mtPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0 );
484         m_M_MissionTime->Wrap( -1 );
485         mtSizer->Add( m_M_MissionTime, 0, wxALL, 2 );
486         mtPanel->SetSizer(mtSizer);
487         mtSizer->Fit(mtPanel);
488         fgSizer9->Add(mtPanel, 0, wxALL, 3);
489
490
491         bSizer->Add( fgSizer9, 0, wxEXPAND, 5 );
492
493
494         bSizer->Add( 0, 0, 0, wxALL, 20 );
495
496         wxBoxSizer* bSizer3 = new wxBoxSizer(wxHORIZONTAL);
497
498         wxBoxSizer* bSizer4 = new wxBoxSizer(wxVERTICAL);
499
500         wxStaticText* m_staticText11 = new wxStaticText( panel, wxID_ANY, wxT("Mission Goals"), wxDefaultPosition, wxDefaultSize, 0 );
501         m_staticText11->Wrap( -1 );
502         bSizer4->Add( m_staticText11, 0, wxALL, 5 );
503
504         m_M_Goals = new wxTreeCtrl( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT|wxTR_NO_BUTTONS );
505
506         wxImageList *goal_imgs = new wxImageList(16, 16);
507
508         goal_imgs->Add( wxBitmap(goal_ord_xpm), wxColour(0xff, 0x0, 0xff) );
509         goal_imgs->Add( wxBitmap(goal_none_xpm), wxColour(0xff, 0xff, 0xff) );
510         goal_imgs->Add( wxBitmap(goal_inc_xpm), wxColour(0xff, 0xff, 0xff) );
511         goal_imgs->Add( wxBitmap(goal_com_xpm), wxColour(0xff, 0xff, 0xff) );
512         goal_imgs->Add( wxBitmap(goal_fail_xpm), wxColour(0xff, 0xff, 0xff) );
513
514         m_M_Goals->AssignImageList(goal_imgs);
515
516         wxTreeItemId root = m_M_Goals->AddRoot( wxT("Goals") );
517
518         m_M_GoalItems[0] = m_M_Goals->AppendItem(root, wxT("Primary Objectives"), 0);
519         m_M_GoalItems[1] = m_M_Goals->AppendItem(root, wxT("Secondary Objectives"), 0);
520         m_M_GoalItems[2] = m_M_Goals->AppendItem(root, wxT("Bonus Objectives"), 0);
521
522         bSizer4->Add( m_M_Goals, 1, wxALL|wxEXPAND, 5 );
523
524         bSizer3->Add(bSizer4, 1, wxEXPAND);
525
526         wxBoxSizer* bSizer5 = new wxBoxSizer(wxVERTICAL);
527
528         wxStaticText* m_staticText12 = new wxStaticText( panel, wxID_ANY, wxT("Netgame Information"), wxDefaultPosition, wxDefaultSize, 0 );
529         m_staticText12->Wrap( -1 );
530         bSizer5->Add( m_staticText12, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
531
532         wxFlexGridSizer* fgSizer11;
533         fgSizer11 = new wxFlexGridSizer( 0, 2, 0, 15 );
534         fgSizer11->AddGrowableRow(0, 1);
535         fgSizer11->AddGrowableRow(1, 1);
536         fgSizer11->AddGrowableRow(2, 1);
537         fgSizer11->AddGrowableRow(3, 1);
538
539         wxStaticText* m_staticText13 = new wxStaticText( panel, wxID_ANY, wxT("Max Players"), wxDefaultPosition, wxDefaultSize, 0 );
540         m_staticText13->Wrap( -1 );
541         fgSizer11->Add( m_staticText13, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
542
543         m_M_ngMaxPlayers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
544         m_M_ngMaxPlayers->Wrap( -1 );
545         fgSizer11->Add( m_M_ngMaxPlayers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
546
547         wxStaticText* m_staticText15 = new wxStaticText( panel, wxID_ANY, wxT("Max Observers"), wxDefaultPosition, wxDefaultSize, 0 );
548         m_staticText15->Wrap( -1 );
549         fgSizer11->Add( m_staticText15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
550
551         m_M_ngMaxObservers = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
552         m_M_ngMaxObservers->Wrap( -1 );
553         fgSizer11->Add( m_M_ngMaxObservers, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
554
555         wxStaticText* m_staticText17 = new wxStaticText( panel, wxID_ANY, wxT("Security"), wxDefaultPosition, wxDefaultSize, 0 );
556         m_staticText17->Wrap( -1 );
557         fgSizer11->Add( m_staticText17, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
558
559         m_M_ngSecurity = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
560         m_M_ngSecurity->Wrap( -1 );
561         fgSizer11->Add( m_M_ngSecurity, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
562
563         wxStaticText* m_staticText19 = new wxStaticText( panel, wxID_ANY, wxT("Respawns"), wxDefaultPosition, wxDefaultSize, 0 );
564         m_staticText19->Wrap( -1 );
565         fgSizer11->Add( m_staticText19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
566
567         m_M_ngRespawns = new wxStaticText( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
568         m_M_ngRespawns->Wrap( -1 );
569         fgSizer11->Add( m_M_ngRespawns, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
570
571         bSizer5->Add( fgSizer11, 1, wxEXPAND );
572
573         bSizer3->Add(bSizer5, 1, wxEXPAND);
574
575         bSizer->Add( bSizer3, 1, wxEXPAND, 5 );
576
577         panelSizer->Add(bSizer, 1, wxALL|wxEXPAND, 5);
578
579         panel->SetSizer( panelSizer );
580         panelSizer->Fit( panel );
581         panelSizer->SetSizeHints( panel );
582
583         parent->AddPage( panel, wxT("Multi-Player") );
584 }
585
586 void Standalone::createTab_Player(wxNotebook* parent)
587 {
588         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
589
590         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
591
592         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
593
594         wxBoxSizer* bSizer21;
595         bSizer21 = new wxBoxSizer( wxHORIZONTAL );
596
597         wxStaticText* m_staticText211 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
598         m_staticText211->Wrap( -1 );
599         bSizer21->Add( m_staticText211, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
600
601         wxArrayString m_choice11Choices;
602         m_P_Players = new wxChoice( panel, ID_C_P_PLAYERS, wxDefaultPosition, wxSize(200, -1), m_choice11Choices, 0 );
603         m_P_Players->SetSelection( wxNOT_FOUND );
604         bSizer21->Add( m_P_Players, 0, wxALL, 5 );
605
606         bSizer->Add( bSizer21, 0, wxEXPAND );
607
608
609         wxStaticLine* m_staticline4 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
610         bSizer->Add( m_staticline4, 0, wxEXPAND | wxALL, 5 );
611
612         wxFlexGridSizer* fgSizer14;
613         fgSizer14 = new wxFlexGridSizer( 0, 2, 0, 0 );
614
615         wxStaticText* m_staticText26 = new wxStaticText( panel, wxID_ANY, wxT("Ship Type"), wxDefaultPosition, wxDefaultSize, 0 );
616         m_staticText26->Wrap( -1 );
617         fgSizer14->Add( m_staticText26, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
618
619         wxPanel* stPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
620         wxBoxSizer* stSizer = new wxBoxSizer(wxHORIZONTAL);
621         m_P_ShipType = new wxStaticText( stPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
622         m_P_ShipType->Wrap( -1 );
623         stSizer->Add(m_P_ShipType, 0, wxALL, 2);
624         stPanel->SetSizer(stSizer);
625         stSizer->Fit(stPanel);
626         fgSizer14->Add( stPanel, 0, wxALL, 5 );
627
628         wxStaticText* m_staticText28 = new wxStaticText( panel, wxID_ANY, wxT("Avg Ping"), wxDefaultPosition, wxDefaultSize, 0 );
629         m_staticText28->Wrap( -1 );
630         fgSizer14->Add( m_staticText28, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
631
632         wxPanel* apPanel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
633         wxBoxSizer* apSizer = new wxBoxSizer(wxHORIZONTAL);
634         m_P_AvgPing = new wxStaticText( apPanel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(150, -1), 0 );
635         m_P_AvgPing->Wrap( -1 );
636         apSizer->Add(m_P_AvgPing, 0, wxALL, 2);
637         apPanel->SetSizer(apSizer);
638         apSizer->Fit(apPanel);
639         fgSizer14->Add( apPanel, 0, wxALL, 5 );
640
641         bSizer->Add( fgSizer14, 0, wxEXPAND );
642
643         bSizer->Add( 0, 0, 0, wxALL, 10);
644
645         wxBoxSizer* bSizer6;
646         bSizer6 = new wxBoxSizer( wxHORIZONTAL );
647
648         //
649         // All-Time Stats
650         //
651
652         wxBoxSizer* atsboxSizer = new wxBoxSizer( wxVERTICAL );
653
654         wxStaticText* atsText = new wxStaticText( panel, wxID_ANY, wxT("All Time Stats") );
655         atsboxSizer->Add( atsText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
656
657         wxFlexGridSizer* atsgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
658         atsgSizer->AddGrowableCol(1, 1);
659
660         // primary shots
661         {
662                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
663                 itxt->Wrap( -1 );
664                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
665                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
666                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
667                 m_P_atsPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
668                 m_P_atsPriShots->Wrap( -1 );
669                 p1sizer->Add( m_P_atsPriShots, 1, wxALL|wxEXPAND, 1);
670                 p1->SetSizer( p1sizer );
671                 p1sizer->Fit( p1 );
672                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
673         }
674
675         // primary hits
676         {
677                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
678                 itxt->Wrap( -1 );
679                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
680                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
681                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
682                 m_P_atsPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
683                 m_P_atsPriHits->Wrap( -1 );
684                 p1sizer->Add( m_P_atsPriHits, 0, wxALL|wxEXPAND, 1);
685                 p1->SetSizer( p1sizer );
686                 p1sizer->Fit( p1 );
687                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
688         }
689
690         // primary BH hits
691         {
692                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
693                 itxt->Wrap( -1 );
694                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
695                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
696                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
697                 m_P_atsPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
698                 m_P_atsPriBHHits->Wrap( -1 );
699                 p1sizer->Add( m_P_atsPriBHHits, 0, wxALL|wxEXPAND, 1);
700                 p1->SetSizer( p1sizer );
701                 p1sizer->Fit( p1 );
702                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
703         }
704
705         // primary hit %
706         {
707                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
708                 itxt->Wrap( -1 );
709                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
710                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
711                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
712                 m_P_atsPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
713                 m_P_atsPriHitPer->Wrap( -1 );
714                 p1sizer->Add( m_P_atsPriHitPer, 0, wxALL|wxEXPAND, 1);
715                 p1->SetSizer( p1sizer );
716                 p1sizer->Fit( p1 );
717                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
718         }
719
720         // primary BH hit %
721         {
722                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
723                 itxt->Wrap( -1 );
724                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
725                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
726                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
727                 m_P_atsPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
728                 m_P_atsPriBHHitPer->Wrap( -1 );
729                 p1sizer->Add( m_P_atsPriBHHitPer, 0, wxALL|wxEXPAND, 1);
730                 p1->SetSizer( p1sizer );
731                 p1sizer->Fit( p1 );
732                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
733         }
734
735         // secondary shots
736         {
737                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
738                 itxt->Wrap( -1 );
739                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
740                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
741                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
742                 m_P_atsSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
743                 m_P_atsSecShots->Wrap( -1 );
744                 p1sizer->Add( m_P_atsSecShots, 0, wxALL|wxEXPAND, 1);
745                 p1->SetSizer( p1sizer );
746                 p1sizer->Fit( p1 );
747                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
748         }
749
750         // secondary hits
751         {
752                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
753                 itxt->Wrap( -1 );
754                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
755                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
756                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
757                 m_P_atsSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
758                 m_P_atsSecHits->Wrap( -1 );
759                 p1sizer->Add( m_P_atsSecHits, 0, wxALL|wxEXPAND, 1);
760                 p1->SetSizer( p1sizer );
761                 p1sizer->Fit( p1 );
762                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
763         }
764
765         // secondary BH hits
766         {
767                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
768                 itxt->Wrap( -1 );
769                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
770                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
771                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
772                 m_P_atsSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
773                 m_P_atsSecBHHits->Wrap( -1 );
774                 p1sizer->Add( m_P_atsSecBHHits, 0, wxALL|wxEXPAND, 1);
775                 p1->SetSizer( p1sizer );
776                 p1sizer->Fit( p1 );
777                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
778         }
779
780         // secondary hit %
781         {
782                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
783                 itxt->Wrap( -1 );
784                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
785                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
786                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
787                 m_P_atsSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
788                 m_P_atsSecHitPer->Wrap( -1 );
789                 p1sizer->Add( m_P_atsSecHitPer, 0, wxALL|wxEXPAND, 1);
790                 p1->SetSizer( p1sizer );
791                 p1sizer->Fit( p1 );
792                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
793         }
794
795         // secondary BH hit %
796         {
797                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
798                 itxt->Wrap( -1 );
799                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
800                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
801                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
802                 m_P_atsSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
803                 m_P_atsSecBHHitPer->Wrap( -1 );
804                 p1sizer->Add( m_P_atsSecBHHitPer, 0, wxALL|wxEXPAND, 1);
805                 p1->SetSizer( p1sizer );
806                 p1sizer->Fit( p1 );
807                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
808         }
809
810         // assists
811         {
812                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
813                 itxt->Wrap( -1 );
814                 atsgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
815                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
816                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
817                 m_P_atsAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
818                 m_P_atsAssists->Wrap( -1 );
819                 p1sizer->Add( m_P_atsAssists, 0, wxALL|wxEXPAND, 1);
820                 p1->SetSizer( p1sizer );
821                 p1sizer->Fit( p1 );
822                 atsgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
823         }
824
825         atsboxSizer->Add( atsgSizer, 1, wxEXPAND );
826
827         bSizer6->Add( atsboxSizer, 1, wxEXPAND, 5 );
828
829         wxStaticLine* m_staticline3 = new wxStaticLine( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
830         bSizer6->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 );
831
832         //
833         // Mission Stats
834         //
835
836         wxBoxSizer* msboxSizer = new wxBoxSizer( wxVERTICAL );
837
838         wxStaticText* msText = new wxStaticText( panel, wxID_ANY, wxT("Mission Stats") );
839         msboxSizer->Add( msText, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
840
841         wxFlexGridSizer* msgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
842         msgSizer->AddGrowableCol(1, 1);
843
844         // primary shots
845         {
846                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
847                 itxt->Wrap( -1 );
848                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
849                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
850                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
851                 m_P_msPriShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
852                 m_P_msPriShots->Wrap( -1 );
853                 p1sizer->Add( m_P_msPriShots, 1, wxALL|wxEXPAND, 1);
854                 p1->SetSizer( p1sizer );
855                 p1sizer->Fit( p1 );
856                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
857         }
858
859         // primary hits
860         {
861                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
862                 itxt->Wrap( -1 );
863                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
864                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
865                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
866                 m_P_msPriHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
867                 m_P_msPriHits->Wrap( -1 );
868                 p1sizer->Add( m_P_msPriHits, 0, wxALL|wxEXPAND, 1);
869                 p1->SetSizer( p1sizer );
870                 p1sizer->Fit( p1 );
871                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
872         }
873
874         // primary BH hits
875         {
876                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
877                 itxt->Wrap( -1 );
878                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
879                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
880                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
881                 m_P_msPriBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
882                 m_P_msPriBHHits->Wrap( -1 );
883                 p1sizer->Add( m_P_msPriBHHits, 0, wxALL|wxEXPAND, 1);
884                 p1->SetSizer( p1sizer );
885                 p1sizer->Fit( p1 );
886                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
887         }
888
889         // primary hit %
890         {
891                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
892                 itxt->Wrap( -1 );
893                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
894                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
895                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
896                 m_P_msPriHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
897                 m_P_msPriHitPer->Wrap( -1 );
898                 p1sizer->Add( m_P_msPriHitPer, 0, wxALL|wxEXPAND, 1);
899                 p1->SetSizer( p1sizer );
900                 p1sizer->Fit( p1 );
901                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
902         }
903
904         // primary BH hit %
905         {
906                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Primary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
907                 itxt->Wrap( -1 );
908                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
909                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
910                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
911                 m_P_msPriBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
912                 m_P_msPriBHHitPer->Wrap( -1 );
913                 p1sizer->Add( m_P_msPriBHHitPer, 0, wxALL|wxEXPAND, 1);
914                 p1->SetSizer( p1sizer );
915                 p1sizer->Fit( p1 );
916                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
917         }
918
919         // secondary shots
920         {
921                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Shots"), wxDefaultPosition, wxDefaultSize, 0 );
922                 itxt->Wrap( -1 );
923                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
924                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
925                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
926                 m_P_msSecShots = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
927                 m_P_msSecShots->Wrap( -1 );
928                 p1sizer->Add( m_P_msSecShots, 0, wxALL|wxEXPAND, 1);
929                 p1->SetSizer( p1sizer );
930                 p1sizer->Fit( p1 );
931                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
932         }
933
934         // secondary hits
935         {
936                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hits"), wxDefaultPosition, wxDefaultSize, 0 );
937                 itxt->Wrap( -1 );
938                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
939                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
940                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
941                 m_P_msSecHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
942                 m_P_msSecHits->Wrap( -1 );
943                 p1sizer->Add( m_P_msSecHits, 0, wxALL|wxEXPAND, 1);
944                 p1->SetSizer( p1sizer );
945                 p1sizer->Fit( p1 );
946                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
947         }
948
949         // secondary BH hits
950         {
951                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hits"), wxDefaultPosition, wxDefaultSize, 0 );
952                 itxt->Wrap( -1 );
953                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
954                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
955                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
956                 m_P_msSecBHHits = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
957                 m_P_msSecBHHits->Wrap( -1 );
958                 p1sizer->Add( m_P_msSecBHHits, 0, wxALL|wxEXPAND, 1);
959                 p1->SetSizer( p1sizer );
960                 p1sizer->Fit( p1 );
961                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
962         }
963
964         // secondary hit %
965         {
966                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
967                 itxt->Wrap( -1 );
968                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
969                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
970                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
971                 m_P_msSecHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
972                 m_P_msSecHitPer->Wrap( -1 );
973                 p1sizer->Add( m_P_msSecHitPer, 0, wxALL|wxEXPAND, 1);
974                 p1->SetSizer( p1sizer );
975                 p1sizer->Fit( p1 );
976                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
977         }
978
979         // secondary BH hit %
980         {
981                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Secondary BH Hit %"), wxDefaultPosition, wxDefaultSize, 0 );
982                 itxt->Wrap( -1 );
983                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
984                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
985                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
986                 m_P_msSecBHHitPer = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
987                 m_P_msSecBHHitPer->Wrap( -1 );
988                 p1sizer->Add( m_P_msSecBHHitPer, 0, wxALL|wxEXPAND, 1);
989                 p1->SetSizer( p1sizer );
990                 p1sizer->Fit( p1 );
991                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
992         }
993
994         // assists
995         {
996                 wxStaticText* itxt = new wxStaticText( panel, wxID_ANY, wxT("Assists"), wxDefaultPosition, wxDefaultSize, 0 );
997                 itxt->Wrap( -1 );
998                 msgSizer->Add( itxt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
999                 wxPanel* p1 = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
1000                 wxBoxSizer* p1sizer = new wxBoxSizer( wxHORIZONTAL );
1001                 m_P_msAssists = new wxStaticText( p1, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
1002                 m_P_msAssists->Wrap( -1 );
1003                 p1sizer->Add( m_P_msAssists, 0, wxALL|wxEXPAND, 1);
1004                 p1->SetSizer( p1sizer );
1005                 p1sizer->Fit( p1 );
1006                 msgSizer->Add( p1, 0, wxALL|wxEXPAND, 1 );
1007         }
1008
1009         msboxSizer->Add( msgSizer, 1, wxEXPAND );
1010
1011         bSizer6->Add( msboxSizer, 1, wxEXPAND );
1012
1013         bSizer->Add( bSizer6, 1, wxEXPAND );
1014
1015         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
1016
1017         panel->SetSizer( panelSizer );
1018         panelSizer->Fit( panel );
1019         panelSizer->SetSizeHints(panel);
1020
1021         parent->AddPage( panel, wxT("Player Info") );
1022 }
1023
1024 void Standalone::createTab_GodStuff(wxNotebook* parent)
1025 {
1026         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
1027
1028         wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
1029
1030         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
1031
1032         wxBoxSizer* bSizer2 = new wxBoxSizer( wxHORIZONTAL );
1033
1034         wxStaticText* m_staticText21 = new wxStaticText( panel, wxID_ANY, wxT("Player"), wxDefaultPosition, wxDefaultSize, 0 );
1035         bSizer2->Add( m_staticText21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
1036
1037         wxArrayString m_choice1Choices;
1038         m_GS_Players = new wxChoice( panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), m_choice1Choices, 0 );
1039         m_GS_Players->SetSelection( wxNOT_FOUND );
1040         bSizer2->Add( m_GS_Players, 0, wxALL|wxEXPAND, 5 );
1041
1042         bSizer->Add( bSizer2, 0, wxEXPAND, 5 );
1043
1044         bSizer->Add( 0, 0, 0, wxALL, 10 );
1045
1046         wxStaticText* m_staticText22 = new wxStaticText( panel, wxID_ANY, wxT("Server Message"), wxDefaultPosition, wxDefaultSize, 0 );
1047         bSizer->Add( m_staticText22, 0, wxALL, 5 );
1048
1049         m_GS_msg = new wxTextCtrl( panel, ID_T_MSG, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
1050         m_GS_msg->SetMaxLength(150);
1051         bSizer->Add( m_GS_msg, 0, wxALL|wxEXPAND, 5 );
1052
1053         bSizer->Add( 0, 0, 0, wxALL, 5 );
1054
1055         m_GS_Messages = new wxTextCtrl( panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY );
1056         bSizer->Add( m_GS_Messages, 1, wxALL|wxEXPAND, 5 );
1057
1058         panelSizer->Add( bSizer, 1, wxALL|wxEXPAND, 5 );
1059
1060         panel->SetSizer( panelSizer );
1061         panelSizer->Fit( panel );
1062         panelSizer->SetSizeHints( panel );
1063
1064         parent->AddPage( panel, wxT("God Stuff") );
1065 }
1066
1067 void Standalone::createTab_Debug(wxNotebook* parent)
1068 {
1069         wxPanel* panel = new wxPanel( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
1070
1071         wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
1072
1073         wxBoxSizer* hbSizer = new wxBoxSizer( wxHORIZONTAL );
1074
1075         wxStaticText* m_staticText1 = new wxStaticText( panel, wxID_ANY, wxT("Standalone State :"), wxDefaultPosition, wxDefaultSize, 0 );
1076         hbSizer->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
1077
1078         wxPanel* p1 = new wxPanel( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER );
1079
1080         wxBoxSizer* p1Sizer = new wxBoxSizer( wxHORIZONTAL );
1081
1082         m_D_State = new wxStaticText( p1, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
1083         p1Sizer->Add( m_D_State, 1, wxALL|wxEXPAND, 2);
1084
1085         p1->SetSizer( p1Sizer );
1086         p1Sizer->Fit( p1 );
1087
1088         hbSizer->Add( p1, 1, wxALL|wxEXPAND, 5 );
1089
1090         bSizer->Add( hbSizer, 0, wxALL|wxEXPAND, 5 );
1091
1092         panel->SetSizer( bSizer );
1093         panel->Layout();
1094
1095         bSizer->Fit( panel );
1096
1097         parent->AddPage( panel, wxT("Debug") );
1098 }
1099
1100 bool Standalone::startFreeSpace(int argc, wxCmdLineArgsArray &argv)
1101 {
1102         wxString epath = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(true);
1103         bool cmd_port = false;
1104
1105 #ifdef MAKE_FS1
1106         epath.Append( wxT("freespace") );
1107 #else
1108         epath.Append( wxT("freespace2") );
1109 #endif
1110
1111 #ifdef FS2_DEMO
1112         epath.Append( wxT("_demo") );
1113 #endif
1114
1115 #ifdef _WIN32
1116         epath.Append( wxT(".exe") );
1117 #endif
1118
1119         epath.Append( wxT(" -standalone") );
1120
1121         for (int i = 1; i < argc; i++) {
1122                 wxString arg( argv[i] );
1123
1124                 // check if -port argument and set var
1125                 if ( arg.IsSameAs( wxT("-port"), false) && (argc > i+1) ) {
1126                         fsport = wxAtoi(argv[i+1]);
1127                         cmd_port = true;
1128                 }
1129
1130                 epath.Append( wxT(" ") );
1131                 epath.Append(arg);
1132         }
1133
1134         // if port isn't specified on cmdline, check ini file for "ForcePort" value
1135         if ( !cmd_port ) {
1136                 char *u_path = SDL_GetPrefPath(Osreg_company_name, Osreg_title);
1137
1138                 if (u_path) {
1139                         wxFileName ini_name(u_path, PROFILE_NAME);
1140                         wxTextFile fs_ini( ini_name.GetFullPath() );
1141
1142                         if ( fs_ini.Open() ) {
1143                                 wxString line;
1144
1145                                 for (line = fs_ini.GetLastLine(); fs_ini.GetCurrentLine() > 0; line = fs_ini.GetPrevLine()) {
1146                                         wxArrayString chk = wxSplit(line, '=');
1147
1148                                         if (chk.GetCount() == 2) {
1149                                                 if (chk.Item(0) == "ForcePort") {
1150                                                         int port = wxAtoi( chk.Item(1) );
1151
1152                                                         if (port > 0) {
1153                                                                 fsport = port;
1154                                                         }
1155
1156                                                         break;
1157                                                 }
1158                                         }
1159                                 }
1160
1161                                 fs_ini.Close();
1162                         }
1163
1164                         SDL_free(u_path);
1165                 }
1166         }
1167
1168         // test if socket is in use (in case exising instance is running on same port)
1169         wxDatagramSocket *sock;
1170         wxIPV4address addr;
1171
1172         addr.AnyAddress();
1173         addr.Service( (unsigned short)fsport );
1174
1175         sock = new wxDatagramSocket(addr);
1176
1177         bool isok = sock->IsOk();
1178
1179         sock->Destroy();
1180
1181         if ( !isok ) {
1182                 throw "Unable to start FreeSpace\n\nAn instance is already running";
1183         }
1184
1185         // start game executable
1186         fspid = wxExecute(epath, wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER | wxEXEC_HIDE_CONSOLE);
1187
1188         return (fspid > 0);
1189 }
1190
1191 void Standalone::ResetAll()
1192 {
1193         m_popup->Show(false);
1194
1195         m_S_ServerName->Clear();
1196         m_S_HostPass->Clear();
1197         m_S_NumConn->SetLabel( wxT("0") );
1198         m_S_Connections->Clear();
1199
1200         m_M_sliderFPS->SetValue(30);
1201         m_M_FPS->SetLabel("30");
1202         m_M_FPSRel->SetLabel( wxT("0.0") );
1203         m_M_MissionName->SetLabel("");
1204         m_M_MissionTime->SetLabel("");
1205         m_M_ngMaxPlayers->SetLabel("");
1206         m_M_ngMaxObservers->SetLabel("");
1207         m_M_ngSecurity->SetLabel("");
1208         m_M_ngRespawns->SetLabel("");
1209
1210         for (int idx = 0; idx < 3; idx++) {
1211                 m_M_Goals->DeleteChildren( m_M_GoalItems[idx] );
1212         }
1213
1214         m_P_Players->Clear();
1215         m_P_ShipType->SetLabel("");
1216         m_P_AvgPing->SetLabel("");
1217         m_P_atsPriShots->SetLabel("");
1218         m_P_atsPriHits->SetLabel("");
1219         m_P_atsPriBHHits->SetLabel("");
1220         m_P_atsPriHitPer->SetLabel("");
1221         m_P_atsPriBHHitPer->SetLabel("");
1222         m_P_atsSecShots->SetLabel("");
1223         m_P_atsSecHits->SetLabel("");
1224         m_P_atsSecBHHits->SetLabel("");
1225         m_P_atsSecHitPer->SetLabel("");
1226         m_P_atsSecBHHitPer->SetLabel("");
1227         m_P_atsAssists->SetLabel("");
1228         m_P_msPriShots->SetLabel("");
1229         m_P_msPriHits->SetLabel("");
1230         m_P_msPriBHHits->SetLabel("");
1231         m_P_msPriHitPer->SetLabel("");
1232         m_P_msPriBHHitPer->SetLabel("");
1233         m_P_msSecShots->SetLabel("");
1234         m_P_msSecHits->SetLabel("");
1235         m_P_msSecBHHits->SetLabel("");
1236         m_P_msSecHitPer->SetLabel("");
1237         m_P_msSecBHHitPer->SetLabel("");
1238         m_P_msAssists->SetLabel("");
1239
1240         m_GS_Players->Clear();
1241         m_GS_msg->Clear();
1242         m_GS_Messages->Clear();
1243
1244         m_D_State->SetLabel("");
1245 }
1246
1247 static int callback_standalone_client(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
1248 {
1249         #define MAX_BUF_SIZE    1050
1250         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BUF_SIZE + LWS_SEND_BUFFER_POST_PADDING];
1251         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
1252         int rval;
1253         int size;
1254
1255         switch (reason) {
1256                 case LWS_CALLBACK_CLIENT_ESTABLISHED:
1257                         lws_callback_on_writable(wsi);
1258                         break;
1259
1260                 case LWS_CALLBACK_CLOSED:
1261                         wxGetApp().Client().wsDisconnect();
1262                         break;
1263
1264                 case LWS_CALLBACK_CLIENT_RECEIVE:
1265                         wxGetApp().Client().wsMessage( (const char *)in, len );
1266                         break;
1267
1268                 case LWS_CALLBACK_CLIENT_WRITEABLE: {
1269                         while ( !wxGetApp().Client().wsGetSendBuffer().empty() ) {
1270                                 std::string msg = wxGetApp().Client().wsGetSendBuffer().front();
1271
1272                                 size = wxStrlcpy((char *)p, msg.c_str(), MAX_BUF_SIZE);
1273
1274                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
1275
1276                                 if (rval < size) {
1277                                         lwsl_err("ERROR sending buffer!\n");
1278                                         return -1;
1279                                 }
1280
1281                                 wxGetApp().Client().wsGetSendBuffer().pop_front();
1282
1283                                 if ( lws_send_pipe_choked(wsi) ) {
1284                                         lws_callback_on_writable(wsi);
1285
1286                                         break;
1287                                 }
1288                         }
1289
1290                         break;
1291                 }
1292
1293                 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
1294                         wxGetApp().Client().wsDisconnect();
1295                         break;
1296
1297                 default:
1298                         break;
1299         }
1300
1301         return 0;
1302 }
1303
1304 static struct lws_protocols protocols[] = {
1305         {
1306                 "standalone",
1307                 callback_standalone_client,
1308                 0,
1309                 0
1310         },
1311         { NULL, NULL, 0, 0 }
1312 };
1313
1314 bool Standalone::wsInitialize()
1315 {
1316         struct lws_context_creation_info info;
1317
1318         memset(&info, 0, sizeof(info));
1319         memset(&ccinfo, 0, sizeof(ccinfo));
1320
1321         info.port = CONTEXT_PORT_NO_LISTEN;
1322         info.protocols = protocols;
1323         info.gid = -1;
1324         info.uid = -1;
1325
1326         stand_context = lws_create_context(&info);
1327
1328         if (stand_context == NULL) {
1329                 return false;
1330         }
1331
1332         ccinfo.context = stand_context;
1333         ccinfo.address = "127.0.0.1";
1334         ccinfo.port = fsport;
1335         ccinfo.path = "/";
1336         ccinfo.host = ccinfo.address;
1337         ccinfo.origin = ccinfo.address;
1338         ccinfo.ietf_version_or_minus_one = -1;
1339         ccinfo.protocol = protocols[0].name;
1340
1341         // async call, actual connection to occur later
1342         wsi_standalone = lws_client_connect_via_info(&ccinfo);
1343
1344         lws_service(stand_context, 0);
1345
1346         return true;
1347 }
1348
1349 void Standalone::wsDoFrame()
1350 {
1351         if ( !stand_context ) {
1352                 return;
1353         }
1354
1355         // if connection is lost attempt reconnect every 2 seconds
1356         if ( !wsi_standalone && !(++m_rate_limit % 60) ) {
1357                 // restart game process if it terminated
1358                 if ( !wxProcess::Exists(fspid) ) {
1359                         wxCmdLineArgsArray empty;
1360
1361                         try {
1362                                 startFreeSpace(0, empty);
1363                         } catch (const char *err) {
1364                                 wxMessageBox(err, "Error!", wxOK|wxICON_ERROR|wxCENTRE|wxSTAY_ON_TOP);
1365
1366                                 Shutdown();
1367                         }
1368
1369                         wxMilliSleep(500);
1370                 }
1371
1372                 wsi_standalone = lws_client_connect_via_info(&ccinfo);
1373                 m_rate_limit = 0;
1374         }
1375
1376         lws_service(stand_context, 0);
1377 }
1378
1379 void Standalone::wsDisconnect()
1380 {
1381         wsi_standalone = NULL;
1382 }
1383
1384 void Standalone::wsMessage(const char *msg, size_t len)
1385 {
1386         if (msg == NULL || len < 5) {
1387                 return;
1388         }
1389
1390         if ( !wxStrcmp(msg, "reset") ) {
1391                 ResetAll();
1392                 return;
1393         }
1394
1395         if ( !wxStrncmp(msg, "popup ", 6) ) {
1396                 if (len == 6) {
1397                         m_popup->Show(false);
1398                 } else {
1399                         wxArrayString popmsg = wxSplit(msg+6, ';');
1400
1401                         m_popup->SetTitle( popmsg.Item(0) );
1402                         m_popup->SetLabel1( popmsg.Item(1) );
1403                         m_popup->SetLabel2( popmsg.Item(2) );
1404
1405                         m_popup->CenterOnParent();
1406                         m_popup->Show(true);
1407                 }
1408
1409                 return;
1410         }
1411
1412         char mtype = msg[0];
1413
1414         if (mtype == 'T') {
1415                 SetTitle(msg+2);
1416         } else if (mtype == 'D') {
1417                 m_D_State->SetLabel(msg+2);
1418         }
1419         // server tab
1420         else if (mtype == 'S') {
1421                 wxString cmd(msg+2, 4);
1422
1423                 if (cmd == "name") {
1424                         m_S_ServerName->SetValue(msg+7);
1425                 } else if (cmd == "pass") {
1426                         m_S_HostPass->SetValue(msg+7);
1427                 } else if (cmd == "conn") {
1428                         wxArrayString conns = wxSplit(msg+7, ';');
1429
1430                         size_t n_conn = conns.size();
1431
1432                         m_S_NumConn->SetLabel( wxString::Format("%u", (unsigned int)n_conn) );
1433
1434                         m_S_Connections->Clear();
1435
1436                         for (size_t idx = 0; idx < n_conn; idx++) {
1437                                 wxArrayString m_conn = wxSplit(conns.Item(idx), ',');
1438
1439                                 m_P_Players->Append( m_conn.Item(0) );
1440                                 m_GS_Players->Append( m_conn.Item(0) );
1441
1442                                 m_S_Connections->AppendText( m_conn.Item(1) + wxT(", \n") );
1443                         }
1444                 } else if (cmd == "ping") {
1445                         wxArrayString ping_list = wxSplit(msg+7, ',');
1446
1447                         size_t n_pings = ping_list.size();
1448
1449                         size_t offset_pos = 0;
1450                         long col = 0, row = 0;
1451
1452                         m_S_Connections->PositionToXY(m_S_Connections->GetInsertionPoint(), &col, &row);
1453
1454                         for (size_t idx = 0; idx < n_pings; idx++) {
1455                                 size_t from_pos = m_S_Connections->GetValue().find(", ", offset_pos);
1456
1457                                 if (from_pos == wxString::npos) {
1458                                         break;
1459                                 } else {
1460                                         from_pos += 2;
1461                                 }
1462
1463                                 size_t to_pos = m_S_Connections->GetValue().find_first_of("\n", from_pos);
1464
1465                                 m_S_Connections->Replace(from_pos, to_pos, ping_list.Item(idx));
1466
1467                                 offset_pos = to_pos;
1468                         }
1469
1470                         // move intersion point to start of original line (avoids accidental kick)
1471                         m_S_Connections->SetInsertionPoint( m_S_Connections->XYToPosition(0, row) );
1472                 }
1473         }
1474         // multi-player tab
1475         else if (mtype == 'M') {
1476                 wxString cmd(msg+2, 4);
1477
1478                 if (cmd == "name") {
1479                         m_M_MissionName->SetLabel(msg+7);
1480                 } else if (cmd == "time") {
1481                         m_M_MissionTime->SetLabel(msg+7);
1482                 } else if (cmd == "info") {
1483                         wxArrayString ng_info = wxSplit(msg+7, ',');
1484
1485                         m_M_ngMaxPlayers->SetLabel( ng_info.Item(0) );
1486                         m_M_ngMaxObservers->SetLabel( ng_info.Item(1) );
1487                         m_M_ngSecurity->SetLabel( ng_info.Item(2) );
1488                         m_M_ngRespawns->SetLabel( ng_info.Item(3) );
1489                 } else if (cmd == "rfps") {
1490                         m_M_FPSRel->SetLabel(msg+7);
1491                 } else if (cmd == "goal") {
1492                         wxArrayString objectives = wxSplit(msg+7, ';');
1493
1494                         size_t n_objectives = objectives.size();
1495                         wxASSERT(n_objectives == 3);
1496
1497                         for (size_t idx = 0; idx < n_objectives; idx++) {
1498                                 wxArrayString goals = wxSplit( objectives.Item(idx), ',' );
1499
1500                                 size_t n_goals = goals.size();
1501
1502                                 m_M_Goals->DeleteChildren(m_M_GoalItems[idx]);
1503
1504                                 for (size_t j = 0; j < n_goals; j++) {
1505                                         char status = goals.Item(j).GetChar(0);
1506                                         wxString goal = goals.Item(j).substr(2);
1507                                         int img = 1;
1508
1509                                         switch (status) {
1510                                                 case 'i': {
1511                                                         if (goal == "none") {
1512                                                                 img = 1;
1513                                                         } else {
1514                                                                 img = 2;
1515                                                         }
1516
1517                                                         break;
1518                                                 }
1519
1520                                                 case 'c':
1521                                                         img = 3;
1522                                                         break;
1523
1524                                                 case 'f':
1525                                                         img = 4;
1526                                                         break;
1527
1528                                                 default:
1529                                                         break;
1530                                         }
1531
1532                                         m_M_Goals->AppendItem(m_M_GoalItems[idx], goal, img);
1533                                 }
1534                         }
1535
1536                         m_M_Goals->ExpandAll();
1537                 }
1538         }
1539         // player tab
1540         else if (mtype == 'P') {
1541                 wxString cmd(msg+2, 4);
1542
1543                 if (cmd == "info") {
1544                         wxArrayString pinfo = wxSplit(msg+7, ';');
1545                         wxArrayString stats;
1546
1547                         m_P_ShipType->SetLabel( pinfo.Item(0) );
1548                         m_P_AvgPing->SetLabel( pinfo.Item(1) );
1549
1550                         stats = wxSplit(pinfo.Item(2), ',');
1551
1552                         m_P_atsPriShots->SetLabel( stats.Item(0) );
1553                         m_P_atsPriHits->SetLabel( stats.Item(1) );
1554                         m_P_atsPriBHHits->SetLabel( stats.Item(2) );
1555                         m_P_atsPriHitPer->SetLabel( stats.Item(3) );
1556                         m_P_atsPriBHHitPer->SetLabel( stats.Item(4) );
1557                         m_P_atsSecShots->SetLabel( stats.Item(5) );
1558                         m_P_atsSecHits->SetLabel( stats.Item(6) );
1559                         m_P_atsSecBHHits->SetLabel( stats.Item(7) );
1560                         m_P_atsSecHitPer->SetLabel( stats.Item(8) );
1561                         m_P_atsSecBHHitPer->SetLabel( stats.Item(9) );
1562                         m_P_atsAssists->SetLabel( stats.Item(10) );
1563
1564                         stats = wxSplit(pinfo.Item(3), ',');
1565
1566                         m_P_msPriShots->SetLabel( stats.Item(0) );
1567                         m_P_msPriHits->SetLabel( stats.Item(1) );
1568                         m_P_msPriBHHits->SetLabel( stats.Item(2) );
1569                         m_P_msPriHitPer->SetLabel( stats.Item(3) );
1570                         m_P_msPriBHHitPer->SetLabel( stats.Item(4) );
1571                         m_P_msSecShots->SetLabel( stats.Item(5) );
1572                         m_P_msSecHits->SetLabel( stats.Item(6) );
1573                         m_P_msSecBHHits->SetLabel( stats.Item(7) );
1574                         m_P_msSecHitPer->SetLabel( stats.Item(8) );
1575                         m_P_msSecBHHitPer->SetLabel( stats.Item(9) );
1576                         m_P_msAssists->SetLabel( stats.Item(10) );
1577                 }
1578         }
1579         // god stuff tab
1580         else if (mtype == 'G') {
1581                 wxString cmd(msg+2, 4);
1582
1583                 if (cmd == "mesg") {
1584                         m_GS_Messages->AppendText(msg+7);
1585                 }
1586         }
1587 }
1588
1589 void Standalone::wsSend(std::string &msg)
1590 {
1591         send_buf.push_back(msg);
1592
1593         if (wsi_standalone) {
1594                 lws_callback_on_writable(wsi_standalone);
1595         }
1596 }