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