1 /////////////////////////////////////////
2 //
3 //             OpenLieroX
4 //
5 // code under LGPL, based on JasonBs work,
6 // enhanced by Dark Charlie and Albert Zeyer
7 //
8 //
9 /////////////////////////////////////////
10 
11 
12 // Net menu - Hosting
13 // Created 12/8/02
14 // Jason Boettcher
15 
16 #include "LieroX.h"
17 #include "IpToCountryDB.h"
18 #include "DeprecatedGUI/Graphics.h"
19 #include "CClient.h"
20 #include "CServer.h"
21 #include "DeprecatedGUI/Menu.h"
22 #include "GfxPrimitives.h"
23 #include "StringUtils.h"
24 #include "CWorm.h"
25 #include "Protocol.h"
26 #include "AuxLib.h"
27 #include "DeprecatedGUI/CLabel.h"
28 #include "DeprecatedGUI/CButton.h"
29 #include "DeprecatedGUI/CListview.h"
30 #include "DeprecatedGUI/CTextbox.h"
31 #include "DeprecatedGUI/CCheckbox.h"
32 #include "DeprecatedGUI/CMenu.h"
33 #include "DeprecatedGUI/CImage.h"
34 #include "DeprecatedGUI/CBox.h"
35 #include "DeprecatedGUI/CGuiSkinnedLayout.h"
36 #include "DeprecatedGUI/CBrowser.h"
37 #include "MathLib.h"
38 #include "Clipboard.h"
39 #include "CClientNetEngine.h"
40 #include "CChannel.h"
41 #include "CServerConnection.h"
42 #include "ProfileSystem.h"
43 #include "Debug.h"
44 #include "console.h"
45 #include "CGameMode.h"
46 #include "DeprecatedGUI/CChatWidget.h"
47 
48 
49 /*
50    The hosting menu is in two parts
51      1) Selecting the players _we_ want to play as
52      2) The lobby screen were other players can connect
53 */
54 
55 
56 
57 /*
58 ==================================
59 
60 		Player selection
61 
62 ==================================
63 */
64 
65 namespace DeprecatedGUI {
66 
67 CGuiLayout	cHostPly;
68 
69 // Player gui
70 enum {
71 	hs_Back=0,
72 	hs_Ok,
73 	hs_PlayerList,
74 	hs_Playing,
75 	hs_Servername,
76 	hs_MaxPlayers,
77 	hs_Register,
78     hs_Password,
79 	hs_WelcomeMessage,
80 	hs_AllowWantsJoin,
81 	hs_WantsJoinBanned,
82 	hs_AllowRemoteBots,
83 	hs_AllowNickChange,
84 	hs_ServerSideHealth
85 };
86 
87 int iHumanPlayers = 0;
88 
89 bool		bSpeedTestDialog = false;
90 bool		bTestedSpeed = false;
91 AbsTime		fHostMenuPlyStart = AbsTime();
92 
93 ///////////////////
94 // Initialize the host menu
Menu_Net_HostInitialize()95 bool Menu_Net_HostInitialize()
96 {
97 	iNetMode = net_host;
98 	iHostType = 0;
99 	bTestedSpeed = false;
100 	bSpeedTestDialog = false;
101 	fHostMenuPlyStart = tLX->currentTime;
102 
103 	// Player gui layout
104 	cHostPly.Shutdown();
105 	cHostPly.Initialize();
106 
107     cHostPly.Add( new CLabel("Player settings",tLX->clHeading), -1, 350,140,0,0);
108 	cHostPly.Add( new CLabel("Server settings",tLX->clHeading), -1, 30, 140,0,0);
109 	cHostPly.Add( new CButton(BUT_BACK, tMenu->bmpButtons), hs_Back,	25, 440,50, 15);
110 	cHostPly.Add( new CButton(BUT_OK, tMenu->bmpButtons),   hs_Ok,			585,440,30, 15);
111 
112 	cHostPly.Add( new CListview(),							hs_PlayerList,	360,160,200,105);
113 	cHostPly.Add( new CListview(),							hs_Playing,		360,275,200,105);
114 	cHostPly.Add( new CLabel("Server name",	tLX->clNormalLabel),		-1,			40, 178,0,  0);
115 	cHostPly.Add( new CTextbox(),							hs_Servername,	175,175,140,tLX->cFont.GetHeight());
116 	cHostPly.Add( new CLabel("Max Players",	tLX->clNormalLabel),		-1,			40,	208,0,  0);
117 	cHostPly.Add( new CTextbox(),							hs_MaxPlayers,	175,205,140,tLX->cFont.GetHeight());
118     //cHostPly.Add( new CLabel("Password",	tLX->clNormalLabel),	    -1,			40, 238,0,  0);
119 	//cHostPly.Add( new CTextbox(),		                    hs_Password,	175,235,140,tLX->cFont.GetHeight());
120 	cHostPly.Add( new CLabel("Welcome Message",	tLX->clNormalLabel),		-1,			40, 238,0,  0);
121 	cHostPly.Add( new CTextbox(),							hs_WelcomeMessage, 175,235,140,tLX->cFont.GetHeight());
122 	cHostPly.Add( new CLabel("Register Server",	tLX->clNormalLabel),	-1,			153, 268,0,  0);
123 	cHostPly.Add( new CCheckbox(false),	                    hs_Register,	270,265,17, 17);
124 	cHostPly.Add( new CLabel("Allow \"Wants to Join\" Messages",	tLX->clNormalLabel),-1,	47, 298,0,  0);
125 	cHostPly.Add( new CCheckbox(false),	                    hs_AllowWantsJoin,	270,295,17, 17);
126 	cHostPly.Add( new CLabel("\"Wants to Join\" from Banned Clients",			tLX->clNormalLabel),-1,	22, 328,0,  0);
127 	cHostPly.Add( new CCheckbox(false),	                    hs_WantsJoinBanned,	270,325,17, 17);
128 	cHostPly.Add( new CLabel("Allow Bots in Server",		tLX->clNormalLabel),-1,	115, 358,0,  0);
129 	cHostPly.Add( new CCheckbox(false),	                    hs_AllowRemoteBots,	270,355,17, 17);
130 	cHostPly.Add( new CLabel("Allow Nick Changing",			tLX->clNormalLabel),-1,	115, 388,0,  0);
131 	cHostPly.Add( new CCheckbox(false),	                    hs_AllowNickChange,	270,385,17, 17);
132 	//cHostPly.Add( new CLabel("Server-side Health",			tLX->clNormalLabel),-1,	125, 418,0,  0);
133 	//cHostPly.Add( new CCheckbox(false),	                    hs_ServerSideHealth,	270,415,17, 17);
134 
135 	Menu_Net_AddTabBarButtons(&cHostPly);
136 
137 	cHostPly.getWidget(hs_Playing)->setKeyboardNavigationOrder(1);
138 	cHostPly.getWidget(hs_Back)->setKeyboardNavigationOrder(1);
139 	cHostPly.getWidget(hs_Ok)->setKeyboardNavigationOrder(1);
140 
141 	cHostPly.SendMessage(hs_Playing,		LVM_SETOLDSTYLE, (DWORD)0, 0);
142 	cHostPly.SendMessage(hs_PlayerList,		LVM_SETOLDSTYLE, (DWORD)0, 0);
143 
144 	cHostPly.SendMessage(hs_Servername,TXM_SETMAX,32,0);
145 	//cHostPly.SendMessage(hs_Password,TXM_SETMAX,32,0);
146 	cHostPly.SendMessage(hs_MaxPlayers,TXM_SETMAX,6,0);
147 
148 	// Use previous settings
149 	cHostPly.SendMessage( hs_MaxPlayers, TXS_SETTEXT, itoa(tLXOptions->tGameInfo.iMaxPlayers), 0);
150 	cHostPly.SendMessage( hs_Servername, TXS_SETTEXT, tLXOptions->sServerName, 0);
151 	cHostPly.SendMessage( hs_WelcomeMessage, TXS_SETTEXT, tLXOptions->sWelcomeMessage, 0);
152 	cHostPly.SendMessage( hs_Register,   CKM_SETCHECK, tLXOptions->bRegServer, 0);
153 	cHostPly.SendMessage( hs_AllowWantsJoin,   CKM_SETCHECK, tLXOptions->bAllowWantsJoinMsg, 0);
154 	cHostPly.SendMessage( hs_WantsJoinBanned,   CKM_SETCHECK, tLXOptions->bWantsJoinBanned, 0);
155 	cHostPly.SendMessage( hs_AllowRemoteBots,   CKM_SETCHECK, tLXOptions->bAllowRemoteBots, 0);
156 	cHostPly.SendMessage( hs_AllowNickChange,   CKM_SETCHECK, tLXOptions->tGameInfo.bAllowNickChange, 0);
157 	//cHostPly.SendMessage( hs_ServerSideHealth,  CKM_SETCHECK, tLXOptions->tGameInfo.bServerSideHealth, 0);
158     //cHostPly.SendMessage( hs_Password,   TXS_SETTEXT, tLXOptions->tGameInfo.szPassword, 0 );
159 
160 	// Add columns
161 	cHostPly.SendMessage( hs_PlayerList,   LVS_ADDCOLUMN, "Players",24);
162 	cHostPly.SendMessage( hs_PlayerList,   LVS_ADDCOLUMN, "",60);
163 	cHostPly.SendMessage( hs_Playing,      LVS_ADDCOLUMN, "Playing",24);
164 	cHostPly.SendMessage( hs_Playing,      LVS_ADDCOLUMN, "",60);
165 
166 	// Add players to the list
167 	profile_t *p = GetProfiles();
168 	for(;p;p=p->tNext) {
169 		/*if(p->iType == PRF_COMPUTER)
170 			continue;*/
171 
172 		cHostPly.SendMessage( hs_PlayerList, LVS_ADDITEM, "", p->iID);
173 		//cHostPly.SendMessage( hs_PlayerList, LVS_ADDSUBITEM, (DWORD)p->bmpWorm, LVS_IMAGE ); // TODO: 64bit unsafe (pointer cast)
174 		//cHostPly.SendMessage( hs_PlayerList, LVS_ADDSUBITEM, p->sName, LVS_TEXT);
175 		CListview * w = (CListview *) cHostPly.getWidget(hs_PlayerList);
176 		w->AddSubitem( LVS_IMAGE, "", p->cSkin.getPreview(), NULL );
177 		w->AddSubitem( LVS_TEXT, p->sName, (DynDrawIntf*)NULL, NULL );
178 	}
179 
180 	iHumanPlayers = 0;
181 
182 	return true;
183 }
184 
185 
186 ///////////////////
187 // Shutdown the host menu
Menu_Net_HostShutdown()188 void Menu_Net_HostShutdown()
189 {
190 	switch(iHostType) {
191 
192 		// Player selection
193 		case 0:
194 			Menu_Net_HostPlyShutdown();
195 			break;
196 
197 		// Lobby
198 		case 1:
199 			Menu_Net_HostLobbyShutdown();
200 			break;
201 	}
202 }
203 
204 
205 ///////////////////
206 // The net host menu frame
Menu_Net_HostFrame(int mouse)207 void Menu_Net_HostFrame(int mouse)
208 {
209 	switch(iHostType) {
210 
211 		// Player selection
212 		case 0:
213 			Menu_Net_HostPlyFrame(mouse);
214 			break;
215 
216 		// Lobby
217 		case 1:
218 			Menu_Net_HostLobbyFrame(mouse);
219 			break;
220 	}
221 }
222 
223 // return value in bytes/second
estimatedMinNeededUploadSpeed(int wormCount,int hostWormCount)224 static float estimatedMinNeededUploadSpeed(int wormCount, int hostWormCount) {
225 	if(wormCount <= 0) return 0.0f;
226 	if(hostWormCount >= wormCount) return 0.0f;
227 
228 	// HINT: This calculation assumes that there is one worm per client. (Except for the local client.)
229 
230 	return
231 		(wormCount - hostWormCount) * // amount of remote worms
232 		(wormCount - 1) * // for each such player, we have to inform about all worms except his own
233 		500.0f; // just an estimation (bytes for worm updates of one single worm)
234 }
235 
maxPossibleWormCountForNetwork(int hostWormCount)236 static int maxPossibleWormCountForNetwork(int hostWormCount) {
237 	int i = 0;
238 	while(i < MAX_PLAYERS) {
239 		if(estimatedMinNeededUploadSpeed(i + 1, hostWormCount) > GameServer::getMaxUploadBandwidth())
240 			return i;
241 		i++;
242 	}
243 	return i;
244 }
245 
246 
247 
248 
Menu_Net_HostUpdateUploadSpeed(float speed)249 void Menu_Net_HostUpdateUploadSpeed(float speed)
250 {
251 	tLXOptions->iMaxUploadBandwidth = (int)speed;
252 
253 	// Update the network speed accordingly
254 	if (tLXOptions->iMaxUploadBandwidth >= 7500)
255 		tLXOptions->iNetworkSpeed = NST_LAN;
256 	else if (tLXOptions->iMaxUploadBandwidth >= 2500)
257 		tLXOptions->iNetworkSpeed = NST_ISDN;
258 	else
259 		tLXOptions->iNetworkSpeed = NST_MODEM;
260 }
261 
262 ///////////////////
263 // Player selection frame
Menu_Net_HostPlyFrame(int mouse)264 void Menu_Net_HostPlyFrame(int mouse)
265 {
266 	gui_event_t *ev = NULL;
267 	CListview	*lv, *lv2;
268 	profile_t	*ply;
269 
270 	// Process & Draw the gui
271 	ev = cHostPly.Process();
272 	cHostPly.Draw( VideoPostProcessor::videoSurface() );
273 
274 	if (Menu_Net_ProcessTabBarButtons(ev))
275 		return;
276 
277 	// Speed test dialog
278 	if (bSpeedTestDialog)  {
279 		if (Menu_SpeedTest_Frame())  {
280 			Menu_Net_HostUpdateUploadSpeed(Menu_SpeedTest_GetSpeed() * 0.9f); // lower a bit to leave some rest free
281 			bSpeedTestDialog = false;
282 			Menu_SpeedTest_Shutdown();
283 		}
284 	}
285 
286 	// If hosting for the first time or the network speed is low, ask for the upload speed test
287 	if (!bDedicated && tLX->currentTime - fHostMenuPlyStart >= 0.5f && !bTestedSpeed)  { // Show a half second after coming to the lobby
288 		if (tLXOptions->bFirstHosting)  {
289 			bTestedSpeed = true;
290 
291 			std::string message = "You are hosting for the first time. To reduce lag, OpenLieroX needs to know the speed of your connection.\n\nDo you want to perform a connection test now?";
292 			if (tLXOptions->iNetworkSpeed == NST_MODEM || tLXOptions->iMaxUploadBandwidth < 5000)
293 				message = "The network speed is set to a very low value. This can cause lag issues on your server. It is recommended to run a connection test.\n\nDo you want to perform a connection test now?";
294 
295 			// TODO: Move that out here. Horrible how many hacks are needed to show a message box
296 			//DrawImage(tMenu->bmpBuffer.get(), VideoPostProcessor::videoSurface(), 0, 0);
297 			if (Menu_MessageBox("Perform a Connection Test", message, LMB_YESNO) == MBR_YES)  {
298 				Menu_SpeedTest_Initialize();
299 				bSpeedTestDialog = true;
300 			}
301 			//Menu_Net_HostLobbyDraw();  // Restore the buffer
302 			//Menu_HostShowMinimap();
303 			//Menu_HostDrawLobby(VideoPostProcessor::videoSurface());
304 		}
305 	}
306 
307 	// Process any events
308 	if(ev) {
309 
310 		switch(ev->iControlID) {
311 
312 			// Back
313 			case hs_Back:
314 				if(ev->iEventMsg == BTN_CLICKED) {
315 
316 					// Click!
317 					PlaySoundSample(sfxGeneral.smpClick);
318 
319 					// Shutdown
320 					Menu_Net_HostShutdown();
321 
322 					// Back to net menu
323 					Menu_MainInitialize();
324 				}
325 				break;
326 
327 
328 			// Player list
329 			case hs_PlayerList:
330 				if(ev->iEventMsg == LV_DOUBLECLK || ev->iEventMsg == LV_RIGHTCLK || ev->iEventMsg == LV_ENTER) {
331 					// Add the item to the players list
332 					lv = (CListview *)cHostPly.getWidget(hs_PlayerList);
333 					lv2 = (CListview *)cHostPly.getWidget(hs_Playing);
334 					int index = lv->getCurIndex();
335 
336 					// Make sure there is 0-NumPlayers players in the list
337 					std::string num_players;
338 					cHostPly.SendMessage(hs_MaxPlayers, TXS_GETTEXT, &num_players, 0);
339 					if(lv2->getItemCount() < MIN((int)MAX_PLAYERS, atoi(num_players))) {
340 						lv->SaveScrollbarPos();
341 
342 						// Get the profile
343 						ply = FindProfile(index);
344 
345 						if(ply) {
346 							if (ply->iType == PRF_COMPUTER->toInt() || iHumanPlayers < 1)  {
347 								lv2->AddItem("",index,tLX->clListView);
348 								lv2->AddSubitem(LVS_IMAGE, "", ply->cSkin.getPreview(), NULL);
349 								lv2->AddSubitem(LVS_TEXT, ply->sName, (DynDrawIntf*)NULL, NULL);
350 								if (ply->iType == PRF_HUMAN->toInt())
351 									iHumanPlayers++;
352 
353 								// Remove the item from the player list
354 								lv->RemoveItem(index);
355 							}
356 						}
357 
358 						lv->RestoreScrollbarPos();
359 
360 					}
361 				}
362 				break;
363 
364 
365 			// Playing list
366 			case hs_Playing:
367 				if(ev->iEventMsg == LV_DOUBLECLK || ev->iEventMsg == LV_RIGHTCLK || ev->iEventMsg == LV_ENTER) {
368 					// Add the item to the players list
369 					lv = (CListview *)cHostPly.getWidget(hs_Playing);
370 					lv2 = (CListview *)cHostPly.getWidget(hs_PlayerList);
371 					int index = lv->getCurIndex();
372 
373 					lv->SaveScrollbarPos();
374 
375 					// Remove the item from the list
376 					lv->RemoveItem(index);
377 
378 					ply = FindProfile(index);
379 
380 					if(ply) {
381 						lv2->AddItem("",index,tLX->clListView);
382 						lv2->AddSubitem(LVS_IMAGE, "", ply->cSkin.getPreview(), NULL);
383 						lv2->AddSubitem(LVS_TEXT, ply->sName, (DynDrawIntf*)NULL, NULL);
384 						if (ply->iType == PRF_HUMAN->toInt())
385 							iHumanPlayers--;
386 					}
387 
388 					lv->RestoreScrollbarPos();
389 				}
390 				break;
391 
392 			// Ok
393 			case hs_Ok:
394 				if(ev->iEventMsg == BTN_CLICKED) {
395 
396 					lv = (CListview *)cHostPly.getWidget(hs_Playing);
397 
398 					if (lv->getItemCount() == 0) {
399 						Menu_MessageBox("Too less players", "You have to select at least one player.");
400 						break;
401 					}
402 
403 					if(lv->getItemCount() > MAX_PLAYERS) {
404 						Menu_MessageBox("Too much players",
405 										"You have selected " + itoa(lv->getItemCount()) + " players "
406 										"but only " + itoa(MAX_PLAYERS) + " players are possible.");
407 						break;
408 					}
409 
410 					std::string buf;
411 					cHostPly.SendMessage( hs_MaxPlayers, TXS_GETTEXT, &buf, 0);
412 					tLXOptions->tGameInfo.iMaxPlayers = atoi(buf);
413 					// At least 2 players, and max MAX_PLAYERS
414 					tLXOptions->tGameInfo.iMaxPlayers = MAX(tLXOptions->tGameInfo.iMaxPlayers,2);
415 					tLXOptions->tGameInfo.iMaxPlayers = MIN(tLXOptions->tGameInfo.iMaxPlayers,MAX_PLAYERS);
416 
417 					if(tLXOptions->bCheckBandwidthSanity || tLXOptions->iNetworkSpeed != NST_LAN) {
418 						float maxRate = GameServer::getMaxUploadBandwidth() / 1024.0f;
419 						float minRate = estimatedMinNeededUploadSpeed(tLXOptions->tGameInfo.iMaxPlayers, lv->getItemCount()) / 1024.0f;
420 						if(maxRate < minRate) {
421 							int maxPossibleWorms = maxPossibleWormCountForNetwork(lv->getItemCount());
422 							notes << "minEstimatedUploadRate=" << minRate << ", maxRate=" << maxRate << ", maxPossibleWorms=" << maxPossibleWorms << endl;
423 							std::string netSettingsText;
424 							switch(tLXOptions->iNetworkSpeed) {
425 								case NST_MODEM: netSettingsText = "Modem"; break;
426 								case NST_ISDN: netSettingsText = "ISDN"; break;
427 								case NST_LAN: netSettingsText = "DSL/LAN"; break;
428 								default: netSettingsText = "???"; break;
429 							}
430 							netSettingsText += ", max " + ftoa(maxRate) + " kB/sec upload";
431 							if(Menu_MessageBox("Check network settings",
432 											   "You allowed " + itoa(tLXOptions->tGameInfo.iMaxPlayers) + " players on your server. "
433 											   "A minimum upload rate of " + ftoa(minRate) + " kB/sec is needed for such an amount.\n"
434 											   "Your current network settings (" + netSettingsText + ") only allow up to " +
435 										   	   itoa(maxPossibleWorms) + " players.\n\n"
436 											   "Would you like to create a server for " + itoa(maxPossibleWorms) + " players?\n"
437 											   "(Otherwise please check your network settings in the option dialog.)",
438 											   LMB_YESNO) == MBR_YES) {
439 								notes << "setting maxplayers to " << maxPossibleWorms << " as user whishes" << endl;
440 								tLXOptions->tGameInfo.iMaxPlayers = maxPossibleWorms;
441 							}
442 							else break;
443 						}
444 					}
445 
446 					tLX->iGameType = GME_HOST;
447 
448 					cClient->Shutdown();
449 				    cClient->Clear();
450 					if(!cClient->Initialize()) {
451 						errors << "Client wouldn't initialize" << endl;
452 						break;
453 					}
454 
455 					// Fill in the game structure
456 					lv_item_t* item;
457 					int count=0;
458 
459 					int i=0;
460 
461 					// Add the human players to the list
462 					for(item = lv->getItems(); item != NULL; item = item->tNext) {
463 						if(item->iIndex < 0)
464 							continue;
465 
466 						profile_t *ply = FindProfile(item->iIndex);
467 
468 						if(ply != NULL && ply->iType == PRF_HUMAN->toInt())  {
469 							// Max two humans
470 							// TODO: extend this
471 							if(i > 2)
472 								break;
473 
474 							cClient->getLocalWormProfiles()[count++] = ply;
475 							i++;
476 						}
477 
478 					}
479 
480 					// Add the unhuman players to the list
481 					for(item = lv->getItems(); item != NULL; item = item->tNext) {
482 						if(item->iIndex < 0)
483 							continue;
484 
485 						profile_t *ply = FindProfile(item->iIndex);
486 
487 						if(ply != NULL && ply->iType != PRF_HUMAN->toInt())  {
488 							cClient->getLocalWormProfiles()[count++] = ply;
489 						}
490 					}
491 					cClient->setNumWorms(count);
492 
493 					// Get the server name
494 					cHostPly.SendMessage( hs_Servername, TXS_GETTEXT, &tLXOptions->sServerName, 0);
495 					cHostPly.SendMessage( hs_WelcomeMessage, TXS_GETTEXT, &tLXOptions->sWelcomeMessage, 0);
496 					//cHostPly.SendMessage( hs_Password, TXS_GETTEXT, &tGameInfo.sPassword, 0);
497 
498 					tLXOptions->bRegServer =  cHostPly.SendMessage( hs_Register, CKM_GETCHECK, (DWORD)0, 0) != 0;
499 					tLXOptions->bAllowWantsJoinMsg = cHostPly.SendMessage( hs_AllowWantsJoin, CKM_GETCHECK, (DWORD)0, 0) != 0;
500 					tLXOptions->bWantsJoinBanned = cHostPly.SendMessage( hs_WantsJoinBanned,   CKM_GETCHECK, (DWORD)0, 0) != 0;
501 					tLXOptions->bAllowRemoteBots = cHostPly.SendMessage( hs_AllowRemoteBots, CKM_GETCHECK, (DWORD)0, 0) != 0;
502 					tLXOptions->tGameInfo.bAllowNickChange = cHostPly.SendMessage( hs_AllowNickChange, CKM_GETCHECK, (DWORD)0, 0) != 0;
503 					tLXOptions->tGameInfo.bServerSideHealth = false; // HINT: disable ssh for normal (non-dedicated) servers, as it is very cheaty
504 					//tLXOptions->tGameInfo.bServerSideHealth = cHostPly.SendMessage( hs_ServerSideHealth, CKM_GETCHECK, (DWORD)0, 0) != 0;
505 
506 					cHostPly.Shutdown();
507 
508 					// Click
509 					PlaySoundSample(sfxGeneral.smpClick);
510 
511 					iHumanPlayers = 0;
512 
513 					// Start the lobby
514 					if (!Menu_Net_HostLobbyInitialize())  {
515 						errors << "could not start hosting lobby menu" << endl;
516 						Menu_Net_HostInitialize();
517 					}
518 				}
519 				break;
520 		}
521 	}
522 
523 
524 	// Draw the mouse
525 	DrawCursor(VideoPostProcessor::videoSurface());
526 }
527 
528 //////////////
529 // Shutdown
Menu_Net_HostPlyShutdown()530 void Menu_Net_HostPlyShutdown()
531 {
532 	cHostPly.Shutdown();
533 }
534 
535 
536 
537 
538 /*
539 ==================================
540 
541 		Hosting Lobby
542 
543 ==================================
544 */
545 
546 
547 // Lobby gui
548 enum {
549 	hl_Back=0,
550 	hl_Start,
551 	hl_ChatText,
552 	hl_ChatList,
553 	hl_LevelList,
554 	hl_PlayerList,
555 	hl_Lives,
556 	hl_MaxKills,
557 	hl_ModName,
558 	hl_Gamemode,
559 	hl_GameSettings,
560     hl_WeaponOptions,
561     hl_PopupMenu,
562 	hl_PopupPlayerInfo,
563 	hl_Banned,
564 	hl_ServerSettings,
565 	hl_StartDedicated,
566 	hl_StartDedicatedSeconds,
567 	hl_StartDedicatedMinPlayers,
568 };
569 
570 bool		bHostGameSettings = false;
571 bool		bHostWeaponRest = false;
572 bool		bBanList = false;
573 bool		bServerSettings = false;
574 CGuiLayout	cHostLobby;
575 int			iSpeaking = 0;
576 int         g_nLobbyWorm = -1;
577 bool		bHost_Update = false;
578 bool		bStartDedicated = false;
579 int			iStartDedicatedSeconds = 15;
580 int			iStartDedicatedMinPlayers = 4;
581 AbsTime		fStartDedicatedSecondsPassed = AbsTime();
582 int			iStartDedicatedServerSpamsSomeInfoTimeout = 15;
583 int			secondsAnnounced = -1;
584 
585 static bool register_vars = CScriptableVars::RegisterVars("GameServer")
586 			( bStartDedicated, "bStartDedicated" )
587 			( iStartDedicatedSeconds, "iStartDedicatedSeconds" )
588 			( iStartDedicatedMinPlayers, "iStartDedicatedMinPlayers" )
589 //			( fStartDedicatedSecondsPassed, "fStartDedicatedSecondsPassed" )
590 			( iStartDedicatedServerSpamsSomeInfoTimeout, "iStartDedicatedServerSpamsSomeInfoTimeout" )
591 			;
592 
593 ///////////////////
594 // Initialize the hosting lobby
Menu_Net_HostLobbyInitialize()595 bool Menu_Net_HostLobbyInitialize()
596 {
597 	tLX->iGameType = GME_HOST;
598 	// TODO: please comment these vars
599 	iNetMode = net_host;
600 	iHostType = 1;
601 	bHostGameSettings = false;
602     bHostWeaponRest = false;
603     iSpeaking = -1;
604 
605 	// Kinda sloppy, but else the background will look sloppy. (Map preview window & the others will be visible
606 	// If put below the client connect. Either this or move the draw.
607 
608 
609 	// Start the server
610 	if(!cServer->StartServer()) {
611 		// Crappy
612 		errors << "Server wouldn't start" << endl;
613 		cHostLobby.Shutdown();
614 		return false;
615 	}
616 
617 	// Lets connect me to the server
618 	cClient->Connect("127.0.0.1:" + itoa(cServer->getPort()));
619 
620 	// Draw the lobby
621 	Menu_Net_HostLobbyDraw();
622 
623 
624 	// Clear the saved chat text
625 	tMenu->sSavedChatText = "";
626 
627     // Create the GUI
628     Menu_Net_HostLobbyCreateGui();
629 
630 	// Add the chat
631 	CBrowser *lv = (CBrowser *)cHostLobby.getWidget(hl_ChatList);
632 	if (lv)  {
633 		lv->InitializeChatBox();
634 		CChatBox *Chatbox = cClient->getChatbox();
635 		lines_iterator it = Chatbox->Begin();
636 
637 		// Copy the chat text
638 		for (int id = 0; it != Chatbox->End(); it++, id++)  {
639 			lv->AddChatBoxLine(it->strLine, it->iColour, it->iTextType);
640 			id++;
641 		}
642 	}
643 
644 	return true;
645 }
646 
647 
648 ///////////////////
649 // Draw the lobby screen
Menu_Net_HostLobbyDraw()650 void Menu_Net_HostLobbyDraw()
651 {
652     // Create the buffer
653 	DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
654 	if (tMenu->tFrontendInfo.bPageBoxes)
655 		Menu_DrawBox(tMenu->bmpBuffer.get(), 5,5, 635, 475);
656 	Menu_DrawBox(tMenu->bmpBuffer.get(), 460,29, 593, 130);
657     DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 281,0, 281,0, 79,20);
658 
659     tLX->cFont.DrawCentre(tMenu->bmpBuffer.get(), 320, -1, tLX->clNormalLabel, "[  Lobby  ]");
660 
661 	// Chat box
662     DrawRectFill(tMenu->bmpBuffer.get(), 16, 270, 624, 417, tLX->clChatBoxBackground);
663 
664 	Menu_RedrawMouse(true);
665 }
666 
667 
668 ///////////////////
669 // Create the lobby gui
Menu_Net_HostLobbyCreateGui()670 void Menu_Net_HostLobbyCreateGui()
671 {
672     // Lobby gui layout
673 	cHostLobby.Shutdown();
674 	cHostLobby.Initialize();
675 
676 	cHostLobby.Add( new CButton(BUT_LEAVE, tMenu->bmpButtons),hl_Back,	15,  450, 60,  15);
677 	cHostLobby.Add( new CButton(BUT_START, tMenu->bmpButtons),hl_Start,	560, 450, 60,  15);
678 	cHostLobby.Add( new CButton(BUT_BANNED, tMenu->bmpButtons),hl_Banned,	450, 450, 90,  15);
679 	cHostLobby.Add( new CButton(BUT_SERVERSETTINGS, tMenu->bmpButtons),hl_ServerSettings,	250, 450, 190, 15);
680     cHostLobby.Add( new CBrowser(),                          hl_ChatList, 15,  268, 610, 150);
681 
682 	cHostLobby.Add( new CButton(BUT_GAMESETTINGS, tMenu->bmpButtons), hl_GameSettings, 360, 210, 170,15);
683     cHostLobby.Add( new CButton(BUT_WEAPONOPTIONS,tMenu->bmpButtons), hl_WeaponOptions,360, 235, 185,15);
684 
685 	cHostLobby.Add( new CLabel("Mod",tLX->clNormalLabel),	    -1,         360, 180, 0,   0);
686 	cHostLobby.Add( new CCombobox(),				hl_ModName,    440, 179, 170, 17);
687 	cHostLobby.Add( new CLabel("Game type",tLX->clNormalLabel),	-1,         360, 158, 0,   0);
688 	cHostLobby.Add( new CCombobox(),				hl_Gamemode,   440, 157, 170, 17);
689     cHostLobby.Add( new CLabel("Level",tLX->clNormalLabel),	    -1,         360, 136, 0,   0);
690     cHostLobby.Add( new CCombobox(),				hl_LevelList,  440, 135, 170, 17);
691 	cHostLobby.Add( new CListview(),				hl_PlayerList, 15, 15, 325, 220);
692 	cHostLobby.Add( new CCheckbox(bStartDedicated),	hl_StartDedicated,			15,  244, 17, 17);
693 	cHostLobby.Add( new CLabel("Auto-start in",tLX->clNormalLabel),	-1,			40,  245, 0,   0);
694 	cHostLobby.Add( new CTextbox(),					hl_StartDedicatedSeconds,	122, 245, 25, tLX->cFont.GetHeight());
695 	cHostLobby.Add( new CLabel("seconds with min",tLX->clNormalLabel),	-1,		155, 245, 0,   0);
696 	cHostLobby.Add( new CTextbox(),					hl_StartDedicatedMinPlayers,263, 245, 25, tLX->cFont.GetHeight());
697 	cHostLobby.Add( new CLabel("players",tLX->clNormalLabel),	-1,				295, 245, 0,   0);
698 
699 	// HINT: must be last, when player presses a key in lobby, this will be the first textbox found
700 	cHostLobby.Add( new CTextbox(),							  hl_ChatText, 15,  421, 610, tLX->cFont.GetHeight());
701 
702 	cHostLobby.SendMessage(hl_StartDedicatedSeconds,TXM_SETMAX,8,0);
703 	cHostLobby.SendMessage(hl_StartDedicatedMinPlayers,TXM_SETMAX,8,0);
704 	CTextbox *t = (CTextbox *)cHostLobby.getWidget(hl_StartDedicatedSeconds);
705 	t->setText( itoa(iStartDedicatedSeconds) );
706 	t = (CTextbox *)cHostLobby.getWidget(hl_StartDedicatedMinPlayers);
707 	t->setText( itoa(iStartDedicatedMinPlayers) );
708 
709 	//cHostLobby.SendMessage(hl_ChatList,		LVM_SETOLDSTYLE, 0, 0);
710 
711 	// Fill in the game details
712 	for(Iterator<CGameMode* const&>::Ref i = GameModeIterator(); i->isValid(); i->next()) {
713 		cHostLobby.SendMessage(hl_Gamemode,    CBS_ADDITEM, i->get()->Name(), GetGameModeIndex(i->get()));
714 	}
715     cHostLobby.SendMessage(hl_Gamemode,    CBM_SETCURSEL, GetGameModeIndex(tLXOptions->tGameInfo.gameMode), 0);
716 
717 	// Fill in the mod list
718 	CCombobox* cbMod = (CCombobox *)cHostLobby.getWidget(hl_ModName);
719 	Menu_Local_FillModList( cbMod );
720 	cbMod->setCurSIndexItem(tLXOptions->tGameInfo.sModDir);
721 
722 	// Fill in the levels list
723 	Menu_FillLevelList( (CCombobox *)cHostLobby.getWidget(hl_LevelList), false);
724 	CCombobox* cbLevel = (CCombobox *) cHostLobby.getWidget(hl_LevelList);
725 	cbLevel->setCurSIndexItem(tLXOptions->tGameInfo.sMapFile);
726 	Menu_HostShowMinimap();
727 
728 	CBrowser *lv = (CBrowser *)cHostLobby.getWidget(hl_ChatList);
729 	lv->InitializeChatBox();
730 
731 	// Don't show chat box selection
732 	//lv->setShowSelect(false);
733 
734 	cHostLobby.SendMessage(hl_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
735 	cHostLobby.SendMessage(hl_ModName,	 CBS_GETCURNAME, &tLXOptions->tGameInfo.sModName, 0);
736 	cHostLobby.SendMessage(hl_ModName,	 CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sModDir, 0);
737 
738 	CCombobox *gtype = (CCombobox *)cHostLobby.getWidget(hl_Gamemode);
739 	if (gtype)  {
740 		gtype->setCurItem( GetGameModeIndex(tLXOptions->tGameInfo.gameMode) );
741 	}
742 
743 	// Setup the player list
744 	CListview *player_list = (CListview *)cHostLobby.getWidget(hl_PlayerList);
745 	if (player_list)  {
746 		player_list->setShowSelect(Menu_IsKeyboardNavigationUsed());
747 		player_list->setOldStyle(true);
748 		player_list->AddColumn("Players", gfxGUI.bmpCommandBtn.get()->w / 2 + 2, tLX->clHeading);  // Command button/Player label
749 		player_list->AddColumn("", tMenu->bmpLobbyReady.get()->w + 2);  // Lobby ready
750 		player_list->AddColumn("", 30);  // Skin
751 		player_list->AddColumn("", 200 - gfxGame.bmpTeamColours[0].get()->w); // Name
752 		player_list->AddColumn("", gfxGame.bmpTeamColours[0].get()->w + 10);  // Team
753 		player_list->AddColumn("", -1); // Ping
754 	}
755 
756 	iSpeaking = 0; // The first player always speaks
757 	fStartDedicatedSecondsPassed = tLX->currentTime;	// Reset timers
758 	cHostLobby.FocusWidget(hl_ChatText);
759 #ifdef __ANDROID__
760 	Menu_WarpMouse(cHostLobby.getWidget(hl_ChatText)->getX() + cHostLobby.getWidget(hl_ChatText)->getWidth() - 2,
761 					cHostLobby.getWidget(hl_ChatText)->getY() + cHostLobby.getWidget(hl_ChatText)->getHeight() - 2);
762 #endif
763 }
764 
765 //////////////////////
766 // Get the content of the chatbox
Menu_Net_HostLobbyGetText()767 std::string Menu_Net_HostLobbyGetText()
768 {
769 	if (tMenu->bMenuRunning)  {
770 		std::string buf;
771 		cHostLobby.SendMessage(hl_ChatText, TXS_GETTEXT, &buf, 256);
772 		return buf;
773 	} else {
774 		return tMenu->sSavedChatText;
775 	}
776 }
777 
778 
Menu_Net_HostLobbySetText(const std::string & str)779 void Menu_Net_HostLobbySetText(const std::string& str) {
780 	cHostLobby.SendMessage(hl_ChatText, TXS_SETTEXT, str, 0);
781 }
782 
783 
784 
785 ///////////////////
786 // Go straight to the lobby, without clearing the server & client
787 // TODO: describe the difference between Menu_Net_GotoHostLobby and Menu_Net_HostGotoLobby
Menu_Net_HostGotoLobby()788 void Menu_Net_HostGotoLobby()
789 {
790 	tLX->iGameType = GME_HOST;
791 	iNetMode = net_host;
792 	iHostType = 1;
793 	bHostGameSettings = false;
794     bHostWeaponRest = false;
795     iSpeaking = 0;
796 
797     // Draw the lobby
798 	if(!bDedicated)
799 		Menu_Net_HostLobbyDraw();
800 
801     if(!bDedicated) {
802 	    // Create the GUI
803     	Menu_Net_HostLobbyCreateGui();
804 
805 		// Add the chat to the chatbox
806 		CBrowser *lv = (CBrowser *)cHostLobby.getWidget(hl_ChatList);
807 		if (lv)  {
808 			lv->InitializeChatBox();
809 			CChatBox *Chatbox = cClient->getChatbox();
810 			lines_iterator it = Chatbox->At((int)Chatbox->getNumLines()-256); // If there's more than 256 messages, we start not from beginning but from end()-256
811 			//int id = (lv->getLastItem() && lv->getItems()) ? lv->getLastItem()->iIndex + 1 : 0;
812 
813 			// Copy the chat text
814 			for (; it != Chatbox->End(); it++)  {
815 				if (it->iTextType == TXT_CHAT || it->iTextType == TXT_PRIVATE || it->iTextType == TXT_TEAMPM )  {  // Add only chat messages
816 					lv->AddChatBoxLine(it->strLine, it->iColour, it->iTextType);
817 					//id++;
818 				}
819 			}
820 
821 			//lv->setShowSelect(false);
822 		}
823 
824 		// Add the ingame chatter text to lobby chatter
825 		cHostLobby.SendMessage(hl_ChatText, TXS_SETTEXT, cClient->chatterText(), 0);
826 	}
827 
828 	cServer->UpdateGameLobby();
829 	tMenu->sSavedChatText = "";
830 }
831 
832 //////////////////////
833 // Change the mod displayed in the lobby
Menu_Net_HostLobbySetMod(const std::string & moddir)834 void Menu_Net_HostLobbySetMod(const std::string& moddir)
835 {
836 	CCombobox *cb = (CCombobox *)cHostLobby.getWidget(hl_ModName);
837 	if (!cb)
838 		return;
839 
840 	cb->setCurSIndexItem(moddir);
841 }
842 
843 /////////////////////
844 // Change level displayed in the lobby
Menu_Net_HostLobbySetLevel(const std::string & filename)845 void Menu_Net_HostLobbySetLevel(const std::string& filename)
846 {
847 	CCombobox *cb = (CCombobox *)cHostLobby.getWidget(hl_LevelList);
848 	if (!cb)
849 		return;
850 
851 	cb->setCurSIndexItem(filename);
852 	Menu_HostShowMinimap();
853 }
854 
855 ///////////////////
856 // Host lobby frame
Menu_Net_HostLobbyFrame(int mouse)857 void Menu_Net_HostLobbyFrame(int mouse)
858 {
859 	gui_event_t *ev = NULL;
860 
861 	// Process the server & client frames
862 	cServer->Frame();
863 	cClient->Frame();
864 
865     // Game settings
866 	if(bHostGameSettings) {
867 		if(Menu_GameSettings_Frame()) {
868 			Menu_Net_HostLobbyDraw();
869 			Menu_HostShowMinimap();
870 
871 			bHostGameSettings = false;
872 
873 			cServer->UpdateGameLobby();
874 
875 			cServer->checkVersionCompatibilities(false);
876 		}
877 		return;
878 	}
879 
880 
881     // Weapons Restrictions
882     if(bHostWeaponRest) {
883 		if(Menu_WeaponsRestrictions_Frame()) {
884 			Menu_Net_HostLobbyDraw();
885 			Menu_HostShowMinimap();
886 
887 			bHostWeaponRest = false;
888 		}
889 		return;
890 	}
891 
892     // Ban List
893     if(bBanList) {
894 		if(Menu_BanList_Frame()) {
895 			Menu_Net_HostLobbyDraw();
896 			Menu_HostShowMinimap();
897 
898 			bBanList = false;
899 		}
900 		return;
901 	}
902 
903     // Server Settings
904     if(bServerSettings) {
905 		if(Menu_ServerSettings_Frame()) {
906 			Menu_Net_HostLobbyDraw();
907 			Menu_HostShowMinimap();
908 
909 			bServerSettings = false;
910 		}
911 		return;
912 	}
913 
914 	// Reload the level and mod list when the user switches back to game
915 	// Do not reaload when any of the dialogs is open
916 	if (bActivated)  {
917 		notes << "Switched back to OLX, re-filling the level and mod lists" << endl;
918 
919 		// Get the mod name
920 		CCombobox* cbMod = (CCombobox *)cHostLobby.getWidget(hl_ModName);
921 		const cb_item_t *it = cbMod->getSelectedItem();
922 		if(it)
923 			tLXOptions->tGameInfo.sModDir = it->sIndex;
924 		else
925 			errors << "No mod is selected, cannot save it to options" << endl;
926 
927 		// Fill in the mod list
928 		Menu_Local_FillModList( cbMod );
929 
930 		// Fill in the levels list
931 		CCombobox* cbLevel = (CCombobox *) cHostLobby.getWidget(hl_LevelList);
932 		it = cbLevel->getSelectedItem();
933 		if(it)
934 			tLXOptions->tGameInfo.sMapFile = it->sIndex;
935 		else
936 			errors << "No level is selected, cannot save it to options" << endl;
937 
938 		Menu_FillLevelList( (CCombobox *)cHostLobby.getWidget(hl_LevelList), false);
939 		cHostLobby.SendMessage(hl_LevelList, CBS_GETCURNAME, &tLXOptions->tGameInfo.sMapName, 0);
940 
941 		Menu_HostShowMinimap();
942 	}
943 
944 
945     // Add chat to the listbox
946 	CBrowser *lv = (CBrowser *)cHostLobby.getWidget(hl_ChatList);
947 	line_t l;
948 
949 	while(cClient->getChatbox()->GetNewLine(l)) {
950 
951         //if(lv->getLastItem() != NULL)
952         lv->AddChatBoxLine(l.strLine, l.iColour, l.iTextType);
953 
954         // If there are too many lines, remove the top one
955         //if(lv->getItemCount() > 256) {
956         //    if(lv->getItems())
957         //        lv->RemoveItem(lv->getItems()->iIndex);
958         //}
959 	}
960 
961 
962 
963     // Clear the chat box & player list & around combo boxes
964     //Menu_redrawBufferRect(25, 315, 590, 100);
965     Menu_redrawBufferRect(15, 20,  335, 225);
966 	Menu_redrawBufferRect(540, 150,  100, 200);
967 
968 	// If any textbox is selected, forbid to show the console
969 	if (cHostLobby.getFocusedWidget() && !Con_IsVisible())  {
970 		tMenu->bForbidConsole = cHostLobby.getFocusedWidget()->getType() == wid_Textbox;
971 	}
972 
973     // Draw the host lobby details
974 	Menu_HostDrawLobby(VideoPostProcessor::videoSurface());
975 
976 	// Process & Draw the gui
977 	if (!Con_IsVisible() && !bSpeedTestDialog && !CChatWidget::GlobalEnabled())  // Don't process when the console is opened or speed test is being performed
978 		ev = cHostLobby.Process();
979 	cHostLobby.Draw( VideoPostProcessor::videoSurface() );
980 	if(CChatWidget::GlobalEnabled())
981 	{
982 		CChatWidget::GlobalProcessAndDraw(VideoPostProcessor::videoSurface());
983 		return;
984 	}
985 
986 	bool bStartPressed = false;
987 
988 	// Process any events
989 	if(ev) {
990 
991 		switch(ev->iControlID) {
992 
993 			// Back
994 			case hl_Back:
995 				if(ev->iEventMsg == BTN_CLICKED) {
996 					// Click!
997 					PlaySoundSample(sfxGeneral.smpClick);
998 
999 					// De-register the server
1000 					Menu_Net_HostDeregister();
1001 
1002 					// Shutdown
1003 					Menu_Net_HostLobbyShutdown();
1004 
1005 					// Back to main net menu
1006 					Menu_NetInitialize();
1007 				}
1008 				break;
1009 
1010 			// Chat box
1011 			case hl_ChatList:
1012 				if (ev->iEventMsg == BRW_KEY_NOT_PROCESSED)  {
1013 					// Activate the textbox automatically
1014 					cHostLobby.FocusWidget(hl_ChatText);
1015 					tMenu->bForbidConsole = true;
1016 
1017 					// Hack: add the just-pressed key to the textbox
1018 					CTextbox *txt = (CTextbox *)cHostLobby.getWidget(hl_ChatText);
1019 					if (txt && GetKeyboard()->queueLength > 0)  {
1020 						KeyboardEvent kbev = GetKeyboard()->keyQueue[GetKeyboard()->queueLength - 1];
1021 						txt->KeyDown(kbev.ch, kbev.sym, *GetCurrentModstate());
1022 					}
1023 				}
1024 				break;
1025 
1026 
1027 			// Chat textbox
1028 			case hl_ChatText:
1029 				if(ev->iEventMsg == TXT_ENTER && iSpeaking >= 0) {
1030 					// Send the msg to the server
1031 
1032 					// Get the text
1033 					std::string text;
1034 					cHostLobby.SendMessage(hl_ChatText, TXS_GETTEXT, &text, 0);
1035 
1036                     // Don't send empty messages
1037                     if(text.size() == 0)
1038                         break;
1039 
1040 					// Clear the text box
1041 					cHostLobby.SendMessage(hl_ChatText, TXS_SETTEXT, "", 0);
1042 
1043 					// Send
1044 					cClient->getNetEngine()->SendText(text, cClient->getWorm(0) ? cClient->getWorm(0)->getName() : "");
1045 				}
1046 				else if(ev->iEventMsg == TXT_TAB) {
1047 					if(strSeemsLikeChatCommand(Menu_Net_HostLobbyGetText())) {
1048 						cClient->getNetEngine()->SendChatCommandCompletionRequest(Menu_Net_HostLobbyGetText().substr(1));
1049 						return;
1050 					}
1051 				}
1052 
1053 				break;
1054 
1055 			// Level change
1056 			case hl_LevelList:
1057 				if(ev->iEventMsg == CMB_CHANGED) {
1058 					Menu_HostShowMinimap();
1059 
1060 					cHostLobby.SendMessage(hl_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
1061 					cServer->UpdateGameLobby();
1062 				}
1063 				break;
1064 
1065             // Mod change
1066             case hl_ModName:
1067                 if(ev->iEventMsg == CMB_CHANGED) {
1068                     cHostLobby.SendMessage(hl_ModName, CBS_GETCURNAME, &tLXOptions->tGameInfo.sModName, 0);
1069                     cHostLobby.SendMessage(hl_ModName, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sModDir, 0);
1070 					cServer->UpdateGameLobby();
1071                 }
1072                 break;
1073 
1074 			// Game type change
1075 			case hl_Gamemode:
1076 				if(ev->iEventMsg == CMB_CHANGED) {
1077 					tLXOptions->tGameInfo.gameMode = GameMode((GameModeIndex)cHostLobby.SendMessage(hl_Gamemode, CBM_GETCURINDEX, (DWORD)0, 0));
1078 					bHost_Update = true;
1079 					cServer->UpdateGameLobby();
1080 				}
1081 				break;
1082 
1083 			// Lives change
1084 			case hl_Lives:
1085 				if(ev->iEventMsg == TXT_CHANGE) {
1086 					std::string buf;
1087 					cHostLobby.SendMessage(hl_Lives, TXS_GETTEXT, &buf, 0);
1088 					TrimSpaces(buf);
1089 					bool fail = false;
1090 					if(buf != "")
1091 						tLXOptions->tGameInfo.iLives = from_string<int>(buf, fail);
1092 					if(buf == "" || fail)
1093 						tLXOptions->tGameInfo.iLives = WRM_UNLIM;
1094 
1095 					cServer->UpdateGameLobby();
1096 				}
1097 				break;
1098 
1099 
1100 			// Max Kills
1101 			case hl_MaxKills:
1102 				if(ev->iEventMsg == TXT_CHANGE) {
1103 					std::string buf;
1104 					cHostLobby.SendMessage(hl_MaxKills, TXS_GETTEXT, &buf, 0);
1105 					TrimSpaces(buf);
1106 					bool fail = false;
1107 					if(buf != "")
1108 						tLXOptions->tGameInfo.iKillLimit = from_string<int>(buf, fail);
1109 					if(buf == "" || fail)
1110 						tLXOptions->tGameInfo.iKillLimit = -2;
1111 
1112 					cServer->UpdateGameLobby();
1113 				}
1114 				break;
1115 
1116 			// Game Settings
1117 			case hl_GameSettings:
1118 				if(ev->iEventMsg == BTN_CLICKED) {
1119 
1120 					// Draw the lobby screen to the buffer
1121 					cHostLobby.Draw(tMenu->bmpBuffer.get());
1122 					Menu_HostDrawLobby(tMenu->bmpBuffer.get());
1123 
1124 					Menu_GameSettings();
1125 					bHostGameSettings = true;
1126 				}
1127 				break;
1128 
1129             // Weapon restrictions
1130             case hl_WeaponOptions:
1131                 if(ev->iEventMsg == BTN_CLICKED) {
1132 
1133                     // Draw the lobby screen to the buffer
1134 					cHostLobby.Draw(tMenu->bmpBuffer.get());
1135 					Menu_HostDrawLobby(tMenu->bmpBuffer.get());
1136 
1137                     cb_item_t *it = (cb_item_t *)cHostLobby.SendMessage(hl_ModName,CBM_GETCURITEM,(DWORD)0,0); // TODO: 64bit unsafe (pointer cast)
1138                     if(it) {
1139 		                bHostWeaponRest = true;
1140 					    Menu_WeaponsRestrictions(it->sIndex);
1141                     }
1142                 }
1143                 break;
1144 
1145 			// Ban list
1146 			case hl_Banned:
1147 				if(ev->iEventMsg == BTN_CLICKED)   {
1148                     // Draw the lobby screen to the buffer
1149 					cHostLobby.Draw(tMenu->bmpBuffer.get());
1150 					Menu_HostDrawLobby(tMenu->bmpBuffer.get());
1151 
1152 	                bBanList = true;
1153 				    Menu_BanList();
1154 				}
1155 				break;
1156 
1157 			// Server settings
1158 			case hl_ServerSettings:
1159 				if(ev->iEventMsg == BTN_CLICKED)   {
1160                     // Draw the lobby screen to the buffer
1161 					cHostLobby.Draw(tMenu->bmpBuffer.get());
1162 					Menu_HostDrawLobby(tMenu->bmpBuffer.get());
1163 
1164 	                bServerSettings = true;
1165 				    Menu_ServerSettings();
1166 				}
1167 				break;
1168 
1169 
1170 			// Start the game
1171 			case hl_Start:
1172 				if(ev->iEventMsg == BTN_CLICKED)
1173 					bStartPressed = true;
1174 				break;
1175 
1176 			// Player list
1177 			case hl_PlayerList:
1178 				if (ev->iEventMsg == LV_WIDGETEVENT)  {
1179 					ev = ((CListview *)ev->cWidget)->getWidgetEvent();
1180 
1181 					// Click on the command button
1182 					if (ev->cWidget->getType() == wid_Button && ev->iEventMsg == BTN_CLICKED)  {
1183 						g_nLobbyWorm = ev->cWidget->getID();
1184 						Menu_HostActionsPopupMenuInitialize(cHostLobby, hl_PopupMenu, hl_PopupPlayerInfo,  g_nLobbyWorm);
1185 					// Click on the team mark
1186 					} else if (ev->cWidget->getType() == wid_Image && ev->iEventMsg == IMG_CLICK)  {
1187 						int id = ev->cWidget->getID();
1188 						if (id >= MAX_WORMS || id < 0 || !cServer->getWorms()) // Safety
1189 							break;
1190 
1191 						// Set the team
1192 						CWorm *w = cServer->getWorms() + id;
1193 						w->setTeam((w->getTeam() + 1) % cServer->getGameMode()->GameTeams());
1194 
1195 						cServer->SendWormLobbyUpdate();  // Update
1196 						bHost_Update = true;
1197 					}
1198 				}
1199 				break;
1200 
1201             // Popup menu
1202 			case hl_PopupMenu:
1203 				if (ev->iEventMsg >= MNU_USER) {
1204 					Menu_HostActionsPopupMenuClick(cHostLobby, hl_PopupMenu, hl_PopupPlayerInfo, g_nLobbyWorm, ev->iEventMsg);
1205 				} else if (ev->iEventMsg == MNU_LOSTFOCUS) {
1206 					// If popup menu not focused, remove it
1207 					cHostLobby.SendMessage(hl_PopupMenu, MNM_REDRAWBUFFER, (DWORD)0, 0);
1208 					cHostLobby.removeWidget(hl_PopupMenu);
1209 					cHostLobby.SendMessage(hl_PopupPlayerInfo, MNM_REDRAWBUFFER, (DWORD)0, 0);
1210 					cHostLobby.removeWidget(hl_PopupPlayerInfo);
1211 				}
1212 				break;
1213 
1214 			case hl_PopupPlayerInfo:
1215 				if (ev->iEventMsg >= MNU_USER) {
1216 					Menu_HostActionsPopupPlayerInfoClick(cHostLobby, hl_PopupMenu, hl_PopupPlayerInfo, g_nLobbyWorm, ev->iEventMsg);
1217 				}
1218 				break;
1219 
1220 			case hl_StartDedicated:
1221 				if(ev->iEventMsg == CHK_CHANGED) {
1222 						CCheckbox *c = (CCheckbox *)cHostLobby.getWidget(hl_StartDedicated);
1223 						bStartDedicated = c->getValue() != 0;
1224 						if( bStartDedicated )
1225 							fStartDedicatedSecondsPassed = tLX->currentTime;
1226 				}
1227                 break;
1228 
1229 			case hl_StartDedicatedSeconds:
1230 				{
1231 					CTextbox *t = (CTextbox *)cHostLobby.getWidget(hl_StartDedicatedSeconds);
1232 					iStartDedicatedSeconds = atoi(t->getText());
1233 				}
1234                 break;
1235 
1236 			case hl_StartDedicatedMinPlayers:
1237 				{
1238 					CTextbox *t = (CTextbox *)cHostLobby.getWidget(hl_StartDedicatedMinPlayers);
1239 					iStartDedicatedMinPlayers = atoi(t->getText());
1240 					iStartDedicatedMinPlayers = CLAMP( iStartDedicatedMinPlayers, 1, tLXOptions->tGameInfo.iMaxPlayers );
1241 				}
1242                 break;
1243 		}
1244 	}
1245 
1246 	if (Menu_IsKeyboardNavigationUsed() && (!cHostLobby.getFocusedWidget() || cHostLobby.getFocusedWidget()->getID() != hl_PopupMenu)) {
1247 		// If popup menu not focused, remove it
1248 		cHostLobby.SendMessage(hl_PopupMenu, MNM_REDRAWBUFFER, (DWORD)0, 0);
1249 		cHostLobby.removeWidget(hl_PopupMenu);
1250 		cHostLobby.SendMessage(hl_PopupPlayerInfo, MNM_REDRAWBUFFER, (DWORD)0, 0);
1251 		cHostLobby.removeWidget(hl_PopupPlayerInfo);
1252 	}
1253 
1254 	// Draw the mouse
1255 	DrawCursor(VideoPostProcessor::videoSurface());
1256 
1257 	int secondsTillGameStart = iStartDedicatedSeconds - Round( (tLX->currentTime - fStartDedicatedSecondsPassed).seconds() );
1258 	if( bStartDedicated && cServer->getNumPlayers() < iStartDedicatedMinPlayers )
1259 	{
1260 		if( tLX->currentTime - fStartDedicatedSecondsPassed > (float)iStartDedicatedServerSpamsSomeInfoTimeout )
1261 		{
1262 			cClient->getNetEngine()->SendText( "Game will start when " +
1263 					itoa(iStartDedicatedMinPlayers) + " players connect", "");
1264 			fStartDedicatedSecondsPassed = tLX->currentTime;
1265 			secondsAnnounced = -1;
1266 		}
1267 	}
1268 	else if( bStartDedicated &&
1269 			( ( secondsTillGameStart != secondsAnnounced ) ||
1270 				secondsAnnounced == -1 ) )
1271 	{
1272 		if( secondsTillGameStart > 0 )
1273 			cClient->getNetEngine()->SendText( "Game will start in " + itoa( secondsTillGameStart ) + " seconds", "" );
1274 		secondsAnnounced = secondsTillGameStart;
1275 	}
1276 
1277 	if( bStartPressed ||
1278 		( bStartDedicated && cServer->getNumPlayers() >= iStartDedicatedMinPlayers && secondsTillGameStart <= 0 ) )
1279 	{
1280 		// Local client will spectate if this is an auto-start (auto-select weapons)
1281 		if (cClient->getWorm(0))  {
1282 			cServer->getWorms()[cClient->getWorm(0)->getID()].setSpectating(!bStartPressed);
1283 		}
1284 
1285 		Menu_Net_HostStartGame();
1286 	}
1287 }
1288 
Menu_Net_HostStartGame()1289 bool Menu_Net_HostStartGame()
1290 {
1291 	secondsAnnounced = -1;
1292 	// Save the chat text
1293 	cHostLobby.SendMessage(hl_ChatText, TXS_GETTEXT, &tMenu->sSavedChatText, 256);
1294 
1295 	// Get the mod
1296 	cb_item_t *it = (cb_item_t *)cHostLobby.SendMessage(hl_ModName,CBM_GETCURITEM,(DWORD)0,0);
1297 	if(it) {
1298 		tLXOptions->tGameInfo.sModName = it->sName;
1299 		tLXOptions->tGameInfo.sModDir = it->sIndex;
1300 	} else {
1301 		errors << "Could not get the selected mod" << endl;
1302 		return false;
1303 	}
1304 
1305 	// Get the game type
1306 	tLXOptions->tGameInfo.gameMode = GameMode((GameModeIndex)cHostLobby.SendMessage(hl_Gamemode, CBM_GETCURINDEX, (DWORD)0, 0));
1307 
1308 	// Start the game
1309 	std::string errMsg;
1310 	if(!cServer->StartGame(&errMsg)) {	// Dedicated if no start button pressed
1311 		errors << "Could not start the game for reason: " << errMsg << endl;
1312 		cClient->getChatbox()->AddText("Error while starting game: " + errMsg, tLX->clNotice, TXT_IMPORTANT, tLX->currentTime);
1313 		return false;
1314 	}
1315 
1316 	// Get the map name
1317 	cHostLobby.SendMessage(hl_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
1318 	cHostLobby.SendMessage(hl_LevelList, CBS_GETCURNAME, &tLXOptions->tGameInfo.sMapName, 0);
1319 	// Save the current level in the options
1320 	cHostLobby.SendMessage(hl_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
1321 	cHostLobby.Shutdown();
1322 
1323 	// Setup the client
1324 	cClient->SetupViewports();
1325 
1326 	// Leave the frontend
1327 	*bGame = true;
1328 	tMenu->bMenuRunning = false;
1329 	tLX->iGameType = GME_HOST;
1330 
1331 	return true;
1332 }
1333 
1334 ////////////////////
1335 // Shutdown
Menu_Net_HostLobbyShutdown()1336 void Menu_Net_HostLobbyShutdown()
1337 {
1338 	// Shutdown all dialogs
1339 	if (bHostGameSettings)
1340 		Menu_GameSettingsShutdown();
1341 	if (bHostWeaponRest)
1342 		Menu_WeaponsRestrictionsShutdown();
1343 	if (bBanList)
1344 		Menu_BanListShutdown();
1345 	if (bServerSettings)
1346 		Menu_ServerSettingsShutdown();
1347 
1348 	// Shutdown
1349 	cHostLobby.Shutdown();
1350 
1351 	// Tell any clients that we're leaving
1352 	cServer->SendDisconnect();
1353 
1354 	// Shutdown server & clients
1355 	cClient->Shutdown();
1356 	cServer->Shutdown();
1357 
1358 	// Recover the host type
1359 	iHostType = 0;
1360 }
1361 
1362 
1363 ///////////////////
1364 // Draw the host lobby screen
Menu_HostDrawLobby(SDL_Surface * bmpDest)1365 void Menu_HostDrawLobby(SDL_Surface * bmpDest)
1366 {
1367 	CListview *player_list = (CListview *)cHostLobby.getWidget(hl_PlayerList);
1368 	if (!player_list) { // Weird, shouldn't happen
1369 		errors << "Menu_HostDrawLobby: player_list not set" << endl;
1370 		return;
1371 	}
1372 
1373 	if(cClient->getRemoteWorms() == NULL) {
1374 		errors << "Menu_HostDrawLobby: remote worms are not initialised" << endl;
1375 		return;
1376 	}
1377 
1378 	// Update the pings first
1379 	CWorm *w = cClient->getRemoteWorms();
1380 	for (int i=0; i < MAX_PLAYERS; i++, w++)  {
1381 		CServerConnection *client = cServer->getClient(w->getID());
1382 		if(!client) continue;
1383 		if(client->isLocalClient()) continue; // don't show ping for host worm
1384 
1385 		lv_subitem_t *subit = player_list->getSubItem(i, 5);
1386 		if (subit)
1387 			subit->sText = itoa(client->getPing());
1388 	}
1389 
1390 
1391 	if (!bHost_Update)  // If no further update is needed, do not do it
1392 		return;
1393 
1394 	player_list->SaveScrollbarPos();
1395 	player_list->Clear();  // Clear any old info
1396 
1397 	w = cServer->getWorms();
1398 	CButton *cmd_button = NULL;
1399 	CImage *team_img = NULL;
1400 
1401 	for (int i=0; i < MAX_PLAYERS; i++, w++)  {
1402 		if (!w->isUsed())  // Don't bother with unused worms
1403 			continue;
1404 
1405 		w->ChangeGraphics(cServer->getGameMode()->GeneralGameType());
1406 
1407 		// Create and setup the command button
1408 		cmd_button = new CButton(0, gfxGUI.bmpCommandBtn);
1409 		if (!cmd_button)
1410 			continue;
1411 		cmd_button->setType(BUT_TWOSTATES);
1412 		cmd_button->setRedrawMenu(false);
1413 		cmd_button->Setup(w->getID(), 0, 0, gfxGUI.bmpCommandBtn.get()->w, gfxGUI.bmpCommandBtn.get()->h);
1414 
1415 		// Add the item
1416 		player_list->AddItem(w->getName(), i, tLX->clNormalLabel);
1417 		player_list->AddSubitem(LVS_WIDGET, "", (DynDrawIntf*)NULL, cmd_button);  // Command button
1418 		if (w->getLobbyReady())  // Ready control
1419 			player_list->AddSubitem(LVS_IMAGE, "", tMenu->bmpLobbyReady, NULL);
1420 		else
1421 			player_list->AddSubitem(LVS_IMAGE, "", tMenu->bmpLobbyNotReady, NULL);
1422 		player_list->AddSubitem(LVS_IMAGE, "", w->getPicimg(), NULL);  // Skin
1423 
1424 		bool compatible = true;
1425 		CServerConnection *client = cServer->getClient(w->getID());
1426 		if(client && !cServer->checkVersionCompatibility(client, false, false)) compatible = false;
1427 		player_list->AddSubitem(LVS_TEXT, "#"+itoa(w->getID())+" "+w->getName(), (DynDrawIntf*)NULL, NULL, VALIGN_MIDDLE,
1428 								compatible ? tLX->clPink : tLX->clError);  // Name
1429 
1430 		// Display the team mark if the game mode requires teams
1431 		if(cServer->getGameMode()->GameTeams() > 1) {
1432 			w->setTeam( CLAMP(w->getTeam(), 0, 4) );
1433 			team_img = new CImage(gfxGame.bmpTeamColours[w->getTeam()]);
1434 			if (!team_img)
1435 				continue;
1436 			team_img->setID(w->getID());
1437 			team_img->setRedrawMenu(false);
1438 
1439 			player_list->AddSubitem(LVS_WIDGET, "", (DynDrawIntf*)NULL, team_img); // Team
1440 
1441 		} else {
1442 			player_list->AddSubitem(LVS_TEXT, "", (DynDrawIntf*)NULL, NULL); // Ping has to be the fifth subitem
1443 		}
1444 
1445 		// Ping
1446 		CServerConnection *cl = cServer->getClient(w->getID());
1447 		int ping = 0;
1448 		if (cl)	ping = cl->getPing();
1449 		player_list->AddSubitem(LVS_TEXT, w->getID() != 0 ? itoa(ping) : "", (DynDrawIntf*)NULL, NULL); // Don't draw for host
1450 	}
1451 
1452 	player_list->RestoreScrollbarPos();  // Scroll back to where we were before
1453 
1454 	// Updated :)
1455 	bHost_Update = false;
1456 }
1457 
1458 
1459 ///////////////////
1460 // Show the minimap
Menu_HostShowMinimap()1461 void Menu_HostShowMinimap()
1462 {
1463 	CMap map;
1464 	std::string buf;
1465 
1466 	cHostLobby.SendMessage(hl_LevelList, CBS_GETCURSINDEX, &buf, 0);
1467 
1468 	// Draw a background over the old minimap
1469 	DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 463,32,463,32,128,96);
1470 
1471 	// Load the map
1472 	map.SetMinimapDimensions(128, 96);
1473 	if(map.Load("levels/"+buf)) {
1474 
1475 		// Draw the minimap
1476 		if(map.GetMiniMap().get())
1477 			DrawImage(tMenu->bmpBuffer.get(), map.GetMiniMap(), 463,32);
1478 		else
1479 			DrawRectFill(tMenu->bmpMiniMapBuffer.get(), 0, 0, tMenu->bmpMiniMapBuffer->w, tMenu->bmpMiniMapBuffer->h, Color());
1480 	} else {
1481 		errors << "Cannot load minimap for level " << buf << endl;
1482 	}
1483 
1484 	// Update the screen
1485 	DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpBuffer, 457,30,457,30,140,110);
1486 }
1487 
1488 
1489 ///////////////////
1490 // Deregister the server
Menu_Net_HostDeregister()1491 void Menu_Net_HostDeregister()
1492 {
1493 	// If the server wasn't registered, just leave
1494 	if( !tLXOptions->bRegServer )
1495 		return;
1496 
1497 	// Initialize the request
1498 	if( !cServer->DeRegisterServer() )
1499 		return;
1500 
1501 
1502 	// Setup the background & show a messagebox
1503 	int x = 160;
1504 	int y = 170;
1505 	int w = 320;
1506 	int h = 140;
1507 	int cx = x+w/2;
1508 	int cy = y+h/2;
1509 
1510 
1511 	DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
1512 	if (tMenu->tFrontendInfo.bPageBoxes)
1513 		Menu_DrawBox(tMenu->bmpBuffer.get(), 15,60, 625, 465);
1514 	Menu_DrawBox(tMenu->bmpBuffer.get(), x, y, x+w, y+h);
1515 	DrawRectFill(tMenu->bmpBuffer.get(), x+2,y+2, x+w-1,y+h-1,tLX->clDialogBackground);
1516 
1517 	tLX->cFont.DrawCentre(tMenu->bmpBuffer.get(), cx, cy, tLX->clNormalLabel, "De-Registering server...");
1518 
1519 	Menu_RedrawMouse(true);
1520 
1521 	AbsTime starttime = tLX->currentTime;
1522 	SetGameCursor(CURSOR_ARROW);
1523 
1524 	while(true) {
1525 		Menu_RedrawMouse(true);
1526 		ProcessEvents();
1527 		tLX->currentTime = GetTime();
1528 
1529 		// If we have gone over a 4 second limit, just leave
1530 		if( tLX->currentTime - starttime > 4.0f ) {
1531 			cServer->getHttp()->CancelProcessing();
1532 			break;
1533 		}
1534 
1535 		if( cServer->ProcessDeRegister() ) {
1536 			cServer->getHttp()->CancelProcessing();
1537 			break;
1538 		}
1539 
1540 		DrawCursor(VideoPostProcessor::videoSurface());
1541 		doVideoFrameInMainThread();
1542 		CapFPS();
1543 	}
1544 }
1545 
1546 /*
1547 =======================
1548 
1549       Server settings
1550 
1551 =======================
1552 */
1553 
1554 
1555 
1556 CGuiLayout		cServerSettings;
1557 
1558 // Server settings dialog
1559 enum {
1560 	ss_Ok,
1561 	ss_Cancel,
1562 	ss_AllowOnlyList,
1563 	ss_WelcomeMessage,
1564 	ss_ServerName,
1565 	ss_AllowWantsJoin,
1566 	ss_WantsJoinBanned,
1567 	ss_AllowRemoteBots,
1568 	ss_AllowNickChange,
1569 	ss_MaxPlayers,
1570 	ss_ServerSideHealth,
1571 	ss_WeaponSelectionMaxTime
1572 };
1573 
1574 
1575 
1576 ///////////////////
1577 // Initialize the server settings window
Menu_ServerSettings()1578 void Menu_ServerSettings()
1579 {
1580 	// Setup the buffer
1581 	//DrawImageAdv(tMenu->bmpBuffer, tMenu->bmpMainBack_common, 120,130,120,130, 400,200);
1582 	DrawRectFillA(tMenu->bmpBuffer.get(), 120,130, 490,445, tLX->clDialogBackground, 200);
1583 	Menu_DrawBox(tMenu->bmpBuffer.get(), 120,130, 490,445);
1584 
1585 	Menu_RedrawMouse(true);
1586 
1587 	cServerSettings.Initialize();
1588 	cServerSettings.Add( new CLabel("Server Settings", tLX->clNormalLabel),		  -1,        275,140,  0, 0);
1589     cServerSettings.Add( new CButton(BUT_OK, tMenu->bmpButtons),	  ss_Ok,	 360,420,  60,15);
1590 	cServerSettings.Add( new CButton(BUT_CANCEL, tMenu->bmpButtons),  ss_Cancel, 220,420,  70,15);
1591 	cServerSettings.Add( new CLabel("Server Name:", tLX->clNormalLabel),		  -1,        130,165,  0, 0);
1592 	cServerSettings.Add( new CLabel("Welcome Message:", tLX->clNormalLabel),	  -1,        130,193,  0, 0);
1593 	cServerSettings.Add( new CLabel("Max. Players:", tLX->clNormalLabel),		  -1,        130,218,  0, 0);
1594 	cServerSettings.Add( new CTextbox(),							  ss_ServerName, 265,165,  200, tLX->cFont.GetHeight());
1595 	cServerSettings.Add( new CTextbox(),							  ss_WelcomeMessage,        265,190,  200, tLX->cFont.GetHeight());
1596 	cServerSettings.Add( new CTextbox(),							  ss_MaxPlayers, 265,215,  50, tLX->cFont.GetHeight());
1597 	cServerSettings.Add( new CLabel("Allow \"Wants to join\" Messages",	tLX->clNormalLabel),-1,	130, 245,0,  0);
1598 	cServerSettings.Add( new CCheckbox(false),		                    ss_AllowWantsJoin,	360,245,17, 17);
1599 	cServerSettings.Add( new CLabel("\"Wants to Join\" from Banned Clients",	tLX->clNormalLabel),-1,	130, 275,0,  0);
1600 	cServerSettings.Add( new CCheckbox(false),		                    ss_WantsJoinBanned,	360,275,17, 17);
1601 	cServerSettings.Add( new CLabel("Allow Bots in Server",				tLX->clNormalLabel),-1,	130, 305,0,  0);
1602 	cServerSettings.Add( new CCheckbox(false),		                    ss_AllowRemoteBots,	360,305,17, 17);
1603 	cServerSettings.Add( new CLabel("Allow Nick Change",				tLX->clNormalLabel),-1,	130, 335,0,  0);
1604 	cServerSettings.Add( new CCheckbox(false),		                    ss_AllowNickChange,	360,335,17, 17);
1605 	//cServerSettings.Add( new CLabel("Server-side Health",				tLX->clNormalLabel),-1,	130, 365,0,  0);
1606 	//cServerSettings.Add( new CCheckbox(false),		                    ss_ServerSideHealth,	360,365,17, 17);
1607 	cServerSettings.Add( new CLabel("Max weapon selection time:",	tLX->clNormalLabel),-1,	130, 365,0,  0);
1608 	cServerSettings.Add( new CTextbox(),							ss_WeaponSelectionMaxTime, 360,365,  30, tLX->cFont.GetHeight());
1609 
1610 	cServerSettings.SendMessage(ss_ServerName,TXM_SETMAX,32,0);
1611 	cServerSettings.SendMessage(ss_WelcomeMessage,TXM_SETMAX,256,0);
1612 	cServerSettings.SendMessage(ss_WeaponSelectionMaxTime,TXM_SETMAX,10,0);
1613 
1614 	// Use the actual settings as default
1615 	cServerSettings.SendMessage(ss_AllowWantsJoin, CKM_SETCHECK, tLXOptions->bAllowWantsJoinMsg, 0);
1616 	cServerSettings.SendMessage(ss_WantsJoinBanned, CKM_SETCHECK, tLXOptions->bWantsJoinBanned, 0);
1617 	cServerSettings.SendMessage(ss_AllowRemoteBots, CKM_SETCHECK, tLXOptions->bAllowRemoteBots, 0);
1618 	cServerSettings.SendMessage(ss_AllowNickChange, CKM_SETCHECK, tLXOptions->tGameInfo.bAllowNickChange, 0);
1619 	//cServerSettings.SendMessage(ss_ServerSideHealth, CKM_SETCHECK, tLXOptions->tGameInfo.bServerSideHealth, 0);
1620 	cServerSettings.SendMessage(ss_ServerName,TXS_SETTEXT,tLXOptions->sServerName, 0);
1621 	cServerSettings.SendMessage(ss_WelcomeMessage,TXS_SETTEXT,tLXOptions->sWelcomeMessage, 0);
1622 	cServerSettings.SendMessage(ss_MaxPlayers, TXS_SETTEXT, itoa(tLXOptions->tGameInfo.iMaxPlayers), 0);
1623 	cServerSettings.SendMessage(ss_WeaponSelectionMaxTime, TXS_SETTEXT, itoa(tLXOptions->tGameInfo.iWeaponSelectionMaxTime), 0);
1624 }
1625 
1626 
1627 ///////////////////
1628 // Server settings frame
1629 // Returns whether or not we have finished setting up the server
Menu_ServerSettings_Frame()1630 bool Menu_ServerSettings_Frame()
1631 {
1632 	gui_event_t *ev = NULL;
1633 
1634 	DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpBuffer, 120,150, 120,150, 400,300);
1635 
1636     // Process events and draw gui
1637 	ev = cServerSettings.Process();
1638 	cServerSettings.Draw(VideoPostProcessor::videoSurface());
1639 
1640 	if(ev) {
1641 
1642 		switch(ev->iControlID) {
1643 
1644 			// OK, done
1645 			case ss_Ok:
1646 				if(ev->iEventMsg == BTN_CLICKED) {
1647 
1648 					// Save the info
1649 					cServerSettings.SendMessage(ss_ServerName, TXS_GETTEXT, &tLXOptions->sServerName, 0);
1650 					cServerSettings.SendMessage(ss_WelcomeMessage,TXS_GETTEXT, &tLXOptions->sWelcomeMessage, 0);
1651 
1652 					std::string buf;
1653 					cServerSettings.SendMessage(ss_MaxPlayers, TXS_GETTEXT, &buf, 0);
1654 					tLXOptions->tGameInfo.iMaxPlayers = atoi(buf);
1655 					// At least 2 players, and max MAX_PLAYERS
1656 					tLXOptions->tGameInfo.iMaxPlayers = MAX(tLXOptions->tGameInfo.iMaxPlayers,2);
1657 					tLXOptions->tGameInfo.iMaxPlayers = MIN(tLXOptions->tGameInfo.iMaxPlayers,MAX_PLAYERS);
1658 
1659 					cServerSettings.SendMessage(ss_WeaponSelectionMaxTime, TXS_GETTEXT, &buf, 0);
1660 					tLXOptions->tGameInfo.iWeaponSelectionMaxTime = MAX( 5, atoi(buf) );	// At least 5 seconds (hit Random - Done)
1661 
1662 					// Set up the server
1663 					if(cServer)  {
1664 						cServer->setName(tLXOptions->sServerName);
1665 					}
1666 
1667 					tLXOptions->bAllowWantsJoinMsg = cServerSettings.SendMessage( ss_AllowWantsJoin, CKM_GETCHECK, (DWORD)0, 0) != 0;
1668 					tLXOptions->bWantsJoinBanned = cServerSettings.SendMessage( ss_WantsJoinBanned, CKM_GETCHECK, (DWORD)0, 0) != 0;
1669 					tLXOptions->bAllowRemoteBots = cServerSettings.SendMessage( ss_AllowRemoteBots, CKM_GETCHECK, (DWORD)0, 0) != 0;
1670 					tLXOptions->tGameInfo.bAllowNickChange = cServerSettings.SendMessage( ss_AllowNickChange, CKM_GETCHECK, (DWORD)0, 0) != 0;
1671 					//tLXOptions->tGameInfo.bServerSideHealth = cServerSettings.SendMessage( ss_ServerSideHealth, CKM_GETCHECK, (DWORD)0, 0) != 0;
1672 
1673 					Menu_ServerSettingsShutdown();
1674 
1675 					return true;
1676 				}
1677 				break;
1678 
1679 			// Cancel, don't save changes
1680 			case ss_Cancel:
1681 				if(ev->iEventMsg == BTN_CLICKED) {
1682 					Menu_ServerSettingsShutdown();
1683 
1684 					return true;
1685 				}
1686 				break;
1687 		}
1688 	}
1689 
1690 	// Draw the mouse
1691 	DrawCursor(VideoPostProcessor::videoSurface());
1692 
1693 	return false;
1694 }
1695 
Menu_ServerSettingsShutdown()1696 void Menu_ServerSettingsShutdown()
1697 {
1698 	cServerSettings.Shutdown();
1699 }
1700 
1701 /*
1702 =======================
1703 
1704       Ban List
1705 
1706 =======================
1707 */
1708 
1709 
1710 
1711 CGuiLayout		cBanListGui;
1712 CBanList        *cBanList = NULL;
1713 
1714 // Ban List
1715 enum {
1716 	bl_Close=0,
1717 	bl_Clear,
1718 	bl_Unban,
1719 	bl_ListBox
1720 };
1721 
1722 
1723 
1724 ///////////////////
1725 // Initialize the ban list window
Menu_BanList()1726 void Menu_BanList()
1727 {
1728 	// Setup the buffer
1729 	DrawImageAdv(tMenu->bmpBuffer.get(), tMenu->bmpMainBack_common, 120,130,120,130, 400,320);
1730 	Menu_DrawBox(tMenu->bmpBuffer.get(), 120,130, 520,440);
1731 	//DrawRectFillA(tMenu->bmpBuffer.get(), 125,155, 380,260, 0, 100);
1732 
1733     CListview *tListBox = new CListview();
1734 
1735 	Menu_RedrawMouse(true);
1736 
1737 	cBanListGui.Initialize();
1738 	cBanListGui.Add( new CLabel("Ban List", tLX->clNormalLabel),     -1,        275,135,  0, 0);
1739     cBanListGui.Add( new CButton(BUT_OK, tMenu->bmpButtons),	  bl_Close,   400,420, 60,15);
1740     cBanListGui.Add( new CButton(BUT_CLEAR, tMenu->bmpButtons),	  bl_Clear,     180,420, 60,15);
1741 	cBanListGui.Add( new CButton(BUT_UNBAN, tMenu->bmpButtons),	  bl_Unban,     260,420, 60,15);
1742 	cBanListGui.Add( tListBox,									  bl_ListBox,125,155, 380,260);
1743 
1744 
1745 	tListBox->AddColumn("IP Address",130);
1746 	tListBox->AddColumn("Nick",160);
1747 
1748 	if (!cServer->getBanList())
1749 		return;
1750 
1751 	// Load the list
1752 	cBanList = cServer->getBanList();
1753 
1754 	tListBox->Clear();
1755 	banlist_t *item;
1756 	for (int i=0;i<(*cBanList).getNumItems(); i++)  {
1757 		item = (*cBanList).getItemById(i);
1758 		if (!item)
1759 			continue;
1760 		tListBox->AddItem(item->szAddress,i,tLX->clListView);
1761 		tListBox->AddSubitem(LVS_TEXT, item->szAddress, (DynDrawIntf*)NULL, NULL);
1762 		tListBox->AddSubitem(LVS_TEXT, item->szNick, (DynDrawIntf*)NULL, NULL);
1763 	}
1764 }
1765 
1766 
1767 ///////////////////
1768 // Ban List frame
1769 // Returns whether or not we have finished with the ban list management
Menu_BanList_Frame()1770 bool Menu_BanList_Frame()
1771 {
1772 	gui_event_t *ev = NULL;
1773 	CListview *tListBox = (CListview *)cBanListGui.getWidget(bl_ListBox);
1774 
1775 
1776 	DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpBuffer, 120,150, 120,150, 400,300);
1777 
1778     // Process events and draw gui
1779 	ev = cBanListGui.Process();
1780 	cBanListGui.Draw(VideoPostProcessor::videoSurface());
1781 
1782 	if(ev) {
1783 
1784 		switch(ev->iControlID) {
1785 
1786 			// Close
1787 			case bl_Close:
1788 				if(ev->iEventMsg == BTN_CLICKED) {
1789 
1790 					Menu_BanListShutdown();
1791 
1792 					return true;
1793 				}
1794 				break;
1795 			// Unban
1796 			case bl_Unban:
1797 				if(ev->iEventMsg == BTN_CLICKED) {
1798 
1799 					if (tListBox->getItemCount() > 0)  {
1800 
1801 						(*cBanList).removeBanned(tListBox->getCurSub()->sText);
1802 
1803 						tListBox->RemoveItem(tListBox->getCurIndex());
1804 					}
1805 				}
1806 				break;
1807 			// Clear
1808 			case bl_Clear:
1809 				if(ev->iEventMsg == BTN_CLICKED) {
1810 					(*cBanList).Clear();
1811 
1812 					tListBox->Clear();
1813 				}
1814 				break;
1815 
1816 		}
1817 	}
1818 
1819 	// Draw the mouse
1820 	DrawCursor(VideoPostProcessor::videoSurface());
1821 
1822 	return false;
1823 }
1824 
1825 //////////////
1826 // Shutdown
Menu_BanListShutdown()1827 void Menu_BanListShutdown()
1828 {
1829 	if (cBanList)
1830 		cBanList->saveList(cBanList->getPath());
1831 	cBanListGui.Shutdown();
1832 }
1833 
Menu_HostActionsPopupMenuInitialize(CGuiLayout & layout,int id_PopupMenu,int id_PopupPlayerInfo,int wormid)1834 void Menu_HostActionsPopupMenuInitialize( CGuiLayout & layout, int id_PopupMenu, int id_PopupPlayerInfo, int wormid )
1835 {
1836 						// Remove old popup menu
1837 						layout.removeWidget(id_PopupMenu);
1838 						cHostLobby.removeWidget(id_PopupPlayerInfo);
1839 
1840 						if (wormid < 0 || wormid >= MAX_WORMS)
1841 							return;
1842 						CWorm *w = &cServer->getWorms()[wormid];
1843 						if (!w->isUsed())
1844 							return;
1845 
1846 						CServerConnection *remote_cl = cServer->getClient(wormid);
1847 						mouse_t *Mouse = GetMouse();
1848 
1849 						CMenu *mnu = NULL;
1850 
1851 						if( !( cServer->getState() == SVS_PLAYING && wormid == 0 ) )	// Do not add the empty menu
1852 						{
1853 							mnu = new CMenu(Mouse->X, Mouse->Y);
1854 							layout.Add(mnu, id_PopupMenu, 0, 0, 640, 480 );
1855 							if (wormid > 0)  {  // These items make no sense for host
1856 								if (tLXOptions->tGameInfo.gameMode->GameTeams() > 1) {
1857 									mnu->addItem(5, "Change team");
1858 								}
1859 								mnu->addItem(0, "Kick player");
1860 								mnu->addItem(1, "Ban player");
1861 								if (remote_cl)  {
1862 									if (remote_cl->getMuted())
1863 										mnu->addItem(2, "Unmute player");
1864 									else
1865 										mnu->addItem(2, "Mute player");
1866 								}
1867 								mnu->addItem(3, "Authorise player");
1868 							}
1869 							if( cServer->getState() != SVS_PLAYING )
1870 								mnu->addItem(4, "Spectator", true, w->isSpectating());
1871 
1872 							layout.FocusWidget(id_PopupMenu);
1873 						}
1874 
1875 						CMenu * info = new CMenu( Mouse->X + (mnu ? mnu->getMenuWidth() : 0) + 10, Mouse->Y );
1876 						if( cServer->getState() == SVS_PLAYING && wormid == 0 ) // Player info is the only popup menu
1877 							layout.Add(info, id_PopupPlayerInfo, 0, 0, 640, 480 );
1878 						else
1879 							layout.Add(info, id_PopupPlayerInfo, info->getMenuX(), info->getMenuY(), 200, 200 );
1880 
1881 						NetworkAddr addr = w->getClient()->getChannel()->getAddress();
1882 						std::string addrStr;
1883 						NetAddrToString(addr, addrStr);
1884 						info->addItem(0, "IP: " + addrStr);
1885 
1886 						if( tIpToCountryDB && tIpToCountryDB->Loaded() )
1887 							info->addItem(1, "Country: " + tIpToCountryDB->GetInfoAboutIP(addrStr).countryName);
1888 
1889 						info->addItem(2, "Version: " + w->getClient()->getClientVersion().asString() );
1890 
1891 						// Update the menu clickable area - all items below are not clickable, they just for info
1892 						if( !( cServer->getState() == SVS_PLAYING && wormid == 0 ) )
1893 							info->Setup(id_PopupPlayerInfo, info->getMenuX(), info->getMenuY(), info->getMenuWidth(), info->getMenuHeight()-2);
1894 
1895 						info->addItem(3, "Received: " + itoa(w->getClient()->getChannel()->getIncoming()/1024) + " Kb");
1896 						info->addItem(4, "Sent: " + itoa(w->getClient()->getChannel()->getOutgoing()/1024) + " Kb");
1897 						info->addItem(5, "Connected for " +
1898 							itoa( (int)((tLX->currentTime - w->getClient()->getConnectTime()).seconds() / 60.0f)) + " minutes");
1899 						info->addItem(6, "Total " +
1900 							itoa( w->getTotalKills() ) + " kills / " +
1901 							itoa( w->getTotalDeaths() ) + " deaths / " +
1902 							itoa( w->getTotalSuicides() ) + " suicides / " +
1903 							itoa( w->getTotalWins() + w->getTotalLosses() ) + " games / " +
1904 							itoa( w->getTotalWins() ) + " wins" );
1905 }
1906 
Menu_HostActionsPopupMenuClick(CGuiLayout & layout,int id_PopupMenu,int id_PopupPlayerInfo,int wormid,int menuItem)1907 void Menu_HostActionsPopupMenuClick(CGuiLayout & layout, int id_PopupMenu, int id_PopupPlayerInfo, int wormid, int menuItem)
1908 {
1909 				CMenu *mnu = (CMenu *)layout.getWidget(id_PopupMenu);
1910                 switch( menuItem ) {
1911 
1912                     // Kick the player
1913                     case MNU_USER+0:
1914 						if( wormid > 0 )
1915                             cServer->kickWorm( wormid, "kicked via GUI menu", false );
1916                         break;
1917 
1918 					// Ban the player
1919 					case MNU_USER+1:
1920 						if ( wormid > 0 )
1921 							cServer->banWorm( wormid, "banned via GUI menu", false );
1922 						break;
1923 
1924 					// Mute/unmute
1925 					case MNU_USER+2:
1926 						if ( wormid > 0 )  {
1927 							CServerConnection *remote_cl = cServer->getClient(wormid);
1928 							if (remote_cl)  {
1929 								if (remote_cl->getMuted())
1930 									cServer->unmuteWorm(wormid);
1931 								else
1932 									cServer->muteWorm(wormid);
1933 							}
1934 						}
1935 						break;
1936 
1937 					// Authorize
1938 					case MNU_USER+3:  {
1939 							CServerConnection *remote_cl = cServer->getClient(wormid);
1940 							if (remote_cl)
1941 								remote_cl->getRights()->Everything();
1942 						} break;
1943 
1944 					// Spectate
1945 					case MNU_USER+4:  {
1946 							if( cServer->getState() == SVS_PLAYING )
1947 								break;
1948 
1949 							if (mnu->getItem(4) && g_nLobbyWorm >= 0 && wormid < MAX_WORMS)  {
1950 								bool spec = mnu->getItem(4)->bChecked;
1951 								CWorm *w = &cServer->getWorms()[wormid];
1952 								w->setSpectating(spec);
1953 								std::string buf;
1954 								if (spec)  {
1955 									if (networkTexts->sIsSpectating != "<none>")
1956 										cServer->SendGlobalText(replacemax(networkTexts->sIsSpectating, "<player>", w->getName(), buf, 1), TXT_NETWORK);
1957 								} else {
1958 									if (networkTexts->sIsPlaying != "<none>")
1959 										cServer->SendGlobalText(replacemax(networkTexts->sIsPlaying, "<player>", w->getName(), buf, 1), TXT_NETWORK);
1960 								}
1961 							}
1962 						} break;
1963 
1964 					// Team
1965 					case MNU_USER+5:  {
1966 							CWorm *w = &cServer->getWorms()[wormid];
1967 							w->setTeam((w->getTeam() + 1) % cServer->getGameMode()->GameTeams());
1968 
1969 							cServer->SendWormLobbyUpdate();  // Update
1970 							bHost_Update = true;
1971 						} break;
1972                 }
1973 
1974                 // Remove the menu widget
1975                 layout.SendMessage( id_PopupMenu, MNM_REDRAWBUFFER, (DWORD)0, 0);
1976                 layout.removeWidget(id_PopupMenu);
1977                 layout.SendMessage( id_PopupPlayerInfo, MNM_REDRAWBUFFER, (DWORD)0, 0);
1978 				layout.removeWidget(id_PopupPlayerInfo);
1979 };
1980 
Menu_HostActionsPopupPlayerInfoClick(CGuiLayout & layout,int id_PopupMenu,int id_PopupPlayerInfo,int wormid,int menuItem)1981 void Menu_HostActionsPopupPlayerInfoClick(CGuiLayout & layout, int id_PopupMenu, int id_PopupPlayerInfo, int wormid, int menuItem)
1982 {
1983 				if (wormid < 0 || wormid >= MAX_WORMS)
1984 					return;
1985 				CWorm *w = &cServer->getWorms()[wormid];
1986 				if (!w->isUsed())
1987 					return;
1988 
1989 				NetworkAddr addr = w->getClient()->getChannel()->getSocket()->remoteAddress();
1990 				std::string addrStr;
1991 				NetAddrToString(addr, addrStr);
1992 
1993                 switch( menuItem ) {
1994 
1995                     case MNU_USER+0:
1996 						copy_to_clipboard(addrStr);
1997                         break;
1998 
1999                     case MNU_USER+1:
2000 						if( tIpToCountryDB->Loaded() )
2001 							copy_to_clipboard(tIpToCountryDB->GetInfoAboutIP(addrStr).countryName);
2002                         break;
2003 
2004                     case MNU_USER+2:
2005 						copy_to_clipboard(w->getClient()->getClientVersion().asString());
2006 						break;
2007 
2008 				};
2009 
2010                 // Remove the menu widget
2011                 layout.SendMessage( id_PopupMenu, MNM_REDRAWBUFFER, (DWORD)0, 0);
2012                 layout.removeWidget(id_PopupMenu);
2013                 layout.SendMessage( id_PopupPlayerInfo, MNM_REDRAWBUFFER, (DWORD)0, 0);
2014 				layout.removeWidget(id_PopupPlayerInfo);
2015 };
2016 
2017 }; // namespace DeprecatedGUI
2018