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