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