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 // Local menu
13 // Created 30/6/02
14 // Jason Boettcher
15 
16 
17 #define DEFAULT_LOADING_TIME 500
18 
19 #include <assert.h>
20 #include <string>
21 
22 #include "LieroX.h"
23 #include "CGameScript.h"
24 #include "AuxLib.h"
25 #include "DeprecatedGUI/Graphics.h"
26 #include "CClient.h"
27 #include "CServer.h"
28 #include "DeprecatedGUI/Menu.h"
29 #include "DeprecatedGUI/CListview.h"
30 #include "GfxPrimitives.h"
31 #include "FindFile.h"
32 #include "StringUtils.h"
33 #include "DeprecatedGUI/CButton.h"
34 #include "DeprecatedGUI/CLabel.h"
35 #include "DeprecatedGUI/CImage.h"
36 #include "DeprecatedGUI/CTextbox.h"
37 #include "DeprecatedGUI/CSlider.h"
38 #include "DeprecatedGUI/CCheckbox.h"
39 #include "DeprecatedGUI/CTextButton.h"
40 #include "DeprecatedGUI/CListview.h"
41 #include "DeprecatedGUI/CGuiSkinnedLayout.h"
42 #include "DeprecatedGUI/CBrowser.h"
43 #include "Sounds.h"
44 #include "ProfileSystem.h"
45 #include "FeatureList.h"
46 #include "Options.h"
47 #include "CGameMode.h"
48 
49 
50 namespace DeprecatedGUI {
51 
52 CGuiLayout cLocalMenu;
53 
54 // Gui layout id's
55 enum {
56 	ml_Back=0,
57 	ml_Start,
58 	ml_Playing,
59 	ml_PlayerList,
60 	ml_LevelList,
61 	ml_Gametype,
62 	ml_ModName,
63 	ml_GameSettings,
64     ml_WeaponOptions
65 };
66 
67 
68 bool	bGameSettings = false;
69 bool    bWeaponRest = false;
70 
71 
72 ///////////////////
73 // Initialize the local menu
Menu_LocalInitialize()74 void Menu_LocalInitialize()
75 {
76 	tMenu->iMenuType = MNU_LOCAL;
77 	bGameSettings = false;
78 
79 	// Create the buffer
80 	DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
81 	Menu_DrawSubTitleAdv(tMenu->bmpBuffer.get(),SUB_LOCAL,15);
82 	if (tMenu->tFrontendInfo.bPageBoxes)
83 		Menu_DrawBox(tMenu->bmpBuffer.get(), 15,100, 625, 465);
84 
85     // Minimap box
86 	Menu_DrawBox(tMenu->bmpBuffer.get(), 133,129, 266, 230);
87 
88 	Menu_RedrawMouse(true);
89 
90 	// Shutdown any previous data from before
91 	cLocalMenu.Shutdown();
92 	cLocalMenu.Initialize();
93 
94 	cLocalMenu.Add( new CButton(BUT_BACK, tMenu->bmpButtons), ml_Back, 27,440, 50,15);
95 	cLocalMenu.Add( new CButton(BUT_START, tMenu->bmpButtons), ml_Start, 555,440, 60,15);
96 	cLocalMenu.Add( new CListview(), ml_PlayerList,  410,115, 200, 126);
97 	cLocalMenu.Add( new CListview(), ml_Playing,     310,250, 300, 185);
98 
99 	cLocalMenu.Add( new CButton(BUT_GAMESETTINGS, tMenu->bmpButtons), ml_GameSettings, 27, 310, 170,15);
100     cLocalMenu.Add( new CButton(BUT_WEAPONOPTIONS,tMenu->bmpButtons), ml_WeaponOptions,27, 335, 185,15);
101 
102 	cLocalMenu.Add( new CLabel("Mod",tLX->clNormalLabel),	    -1,         30,  284, 0,   0);
103 	cLocalMenu.Add( new CCombobox(),				ml_ModName,    120, 283, 170, 17);
104 	cLocalMenu.Add( new CLabel("Game type",tLX->clNormalLabel),	-1,         30,  260, 0,   0);
105 	cLocalMenu.Add( new CCombobox(),				ml_Gametype,   120, 259, 170, 17);
106     cLocalMenu.Add( new CLabel("Level",tLX->clNormalLabel),	    -1,         30,  236, 0,   0);
107 	cLocalMenu.Add( new CCombobox(),				ml_LevelList,  120, 235, 170, 17);
108 
109 	cLocalMenu.getWidget(ml_Playing)->setKeyboardNavigationOrder(1);
110 	cLocalMenu.getWidget(ml_Back)->setKeyboardNavigationOrder(1);
111 	cLocalMenu.getWidget(ml_Start)->setKeyboardNavigationOrder(1);
112 
113 	cLocalMenu.SendMessage(ml_Playing,		LVS_ADDCOLUMN, "Playing", 24);
114 	cLocalMenu.SendMessage(ml_Playing,		LVS_ADDCOLUMN, "", 300 - gfxGame.bmpTeamColours[0].get()->w - 50);
115 	cLocalMenu.SendMessage(ml_Playing,		LVS_ADDCOLUMN, "", (DWORD)-1);
116 
117 	cLocalMenu.SendMessage(ml_Playing,		LVM_SETOLDSTYLE, (DWORD)1, 0);
118 
119 	cLocalMenu.SendMessage(ml_PlayerList,	LVS_ADDCOLUMN, "Players", 24);
120 	cLocalMenu.SendMessage(ml_PlayerList,	LVS_ADDCOLUMN, "", 60);
121 
122 	cLocalMenu.SendMessage(ml_PlayerList,		LVM_SETOLDSTYLE, (DWORD)0, 0);
123 
124 	for(Iterator<CGameMode* const&>::Ref i = GameModeIterator(); i->isValid(); i->next()) {
125 		cLocalMenu.SendMessage(ml_Gametype,    CBS_ADDITEM, i->get()->Name(), GetGameModeIndex(i->get()));
126 	}
127     cLocalMenu.SendMessage(ml_Gametype,    CBM_SETCURSEL, GetGameModeIndex(tLXOptions->tGameInfo.gameMode), 0);
128 
129 	// Add players to player/playing lists
130 	Menu_LocalAddProfiles();
131 
132 	// Fill the level list
133 	CCombobox* cbLevel = (CCombobox *)cLocalMenu.getWidget(ml_LevelList);
134 	Menu_FillLevelList( cbLevel, true);
135 	cbLevel->setCurItem(cbLevel->getSIndexItem(tLXOptions->tGameInfo.sMapFile));
136 	Menu_LocalShowMinimap(true);
137 
138 	// Fill in the mod list
139 	CCombobox* cbMod = (CCombobox *)cLocalMenu.getWidget(ml_ModName);
140 	Menu_Local_FillModList( cbMod );
141 	cbMod->setCurItem(cbMod->getSIndexItem(tLXOptions->tGameInfo.sModDir));
142 
143 }
144 
145 //////////////
146 // Shutdown
Menu_LocalShutdown()147 void Menu_LocalShutdown()
148 {
149 	if (bGameSettings)
150 		Menu_GameSettingsShutdown();
151 	if (bWeaponRest)
152 		Menu_WeaponsRestrictionsShutdown();
153 
154 
155 	// Save the level and mod
156 	if (tLXOptions)  {
157 		cLocalMenu.SendMessage(ml_LevelList,CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
158 		cLocalMenu.SendMessage(ml_ModName,CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sModDir, 0);
159 	}
160 
161 	cLocalMenu.Shutdown();
162 }
163 
164 
165 ///////////////////
166 // Local frame
Menu_LocalFrame()167 void Menu_LocalFrame()
168 {
169 	gui_event_t *ev = NULL;
170 	mouse_t *Mouse = GetMouse();
171 	CListview *lv;
172 
173     // Game Settings
174 	if(bGameSettings) {
175 		if(Menu_GameSettings_Frame()) {
176 			// Re-do the buffer
177 			DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
178 	        Menu_DrawSubTitleAdv(tMenu->bmpBuffer.get(),SUB_LOCAL,15);
179 			if (tMenu->tFrontendInfo.bPageBoxes)
180 				Menu_DrawBox(tMenu->bmpBuffer.get(), 15,100, 625, 465);
181 	        Menu_DrawBox(tMenu->bmpBuffer.get(), 133,129, 266, 230);
182 
183 			Menu_RedrawMouse(true);
184 			Menu_LocalShowMinimap(false);
185 
186 			bGameSettings = false;
187 		}
188 		return;
189 	}
190 
191 
192     // Weapons Restrictions
193     if(bWeaponRest) {
194 		if(Menu_WeaponsRestrictions_Frame()) {
195 			// Re-do the buffer
196 			DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
197 	        Menu_DrawSubTitleAdv(tMenu->bmpBuffer.get(),SUB_LOCAL,15);
198 			if (tMenu->tFrontendInfo.bPageBoxes)
199 				Menu_DrawBox(tMenu->bmpBuffer.get(), 15,100, 625, 465);
200 	        Menu_DrawBox(tMenu->bmpBuffer.get(), 133,129, 266, 230);
201 
202 			Menu_RedrawMouse(true);
203 			Menu_LocalShowMinimap(false);
204 
205 			bWeaponRest = false;
206 		}
207 		return;
208 	}
209 
210 	// Reload the list if user switches back to the game
211 	// Do not reload when a dialog is open
212 	if (bActivated)  {
213 		// Get the mod name
214 		CCombobox* cbMod = (CCombobox *)cLocalMenu.getWidget(ml_ModName);
215 		const cb_item_t *it = cbMod->getItem(cbMod->getSelectedIndex());
216 		if(it) tLXOptions->tGameInfo.sModDir = it->sIndex;
217 
218 		// Fill in the mod list
219 		Menu_Local_FillModList( cbMod );
220 		cbMod->setCurItem(cbMod->getSIndexItem(tLXOptions->tGameInfo.sModDir));
221 
222 		// Fill in the levels list
223 		CCombobox* cbLevel = (CCombobox *)cLocalMenu.getWidget(ml_LevelList);
224 		const cb_item_t *item = cbLevel->getItem( cbLevel->getSelectedIndex() );
225 		if (item)
226 			tLXOptions->tGameInfo.sMapFile = item->sIndex;
227 		Menu_FillLevelList( cbLevel, true);
228 		cbLevel->setCurItem(cbLevel->getSIndexItem(tLXOptions->tGameInfo.sMapFile));
229 
230 		// Reload the minimap
231 		//if (tLXOptions->tGameInfo.sMapFile != "_random_")
232 		Menu_LocalShowMinimap(true);
233 	}
234 
235 
236     // Was the mouse clicked on the map section
237     if( Mouse->Up & SDL_BUTTON(1) ) {
238     	// TODO: hardcoded sizes here
239         if( MouseInRect(136,132,128,96) )
240 	    	// TODO: why are we redrawing the minimap here?
241             Menu_LocalShowMinimap(true);
242     }
243 
244 
245 	ev = cLocalMenu.Process();
246 	cLocalMenu.Draw(VideoPostProcessor::videoSurface());
247 
248 	if(ev) {
249 		int changeTeamPlayerId = -1;
250 
251 		switch(ev->iControlID) {
252 			// Back
253 			case ml_Back:
254 				if(ev->iEventMsg == BTN_CLICKED) {
255 
256 					// Shutdown
257 					Menu_LocalShutdown();
258 
259 					// Leave
260 					PlaySoundSample(sfxGeneral.smpClick);
261 					Menu_MainInitialize();
262 					return;
263 				}
264 				break;
265 
266 			// Start
267 			case ml_Start:
268 				if(ev->iEventMsg == BTN_CLICKED) {
269 					PlaySoundSample(sfxGeneral.smpClick);
270 
271 					// Start the game
272 					Menu_LocalStartGame();
273 				}
274 				break;
275 
276 			// Player list
277 			case ml_PlayerList:
278 				if(ev->iEventMsg == LV_DOUBLECLK || ev->iEventMsg == LV_RIGHTCLK || ev->iEventMsg == LV_ENTER) {
279 					Menu_LocalAddPlaying();
280 				}
281 				break;
282 
283 			// Playing list
284 			case ml_Playing:
285 				if (ev->iEventMsg == LV_DOUBLECLK || ev->iEventMsg == LV_RIGHTCLK || ev->iEventMsg == LV_ENTER) {
286 					if (!Menu_IsKeyboardNavigationUsed() || tLXOptions->tGameInfo.gameMode->GameTeams() <= 1)
287 						Menu_LocalRemovePlaying();
288 				}
289 
290 				lv = (CListview *)cLocalMenu.getWidget(ml_Playing);
291 
292 				if (tLXOptions->tGameInfo.gameMode->GameTeams() > 1 && ev->iEventMsg == LV_WIDGETEVENT) {
293 					// If the team colour item was clicked on, change it
294 					ev = lv->getWidgetEvent();
295 					if (ev->cWidget->getType() == wid_Image && ev->iEventMsg == IMG_CLICK)  {
296 						changeTeamPlayerId = ev->iControlID;
297 					}
298 					if (Menu_IsKeyboardNavigationUsed()) {
299 						changeTeamPlayerId = lv->getCurIndex();
300 					}
301 				}
302 
303 				if (changeTeamPlayerId >= 0) {
304 					lv_item_t *it = lv->getItem(changeTeamPlayerId);
305 					lv_subitem_t *sub = lv->getSubItem(it, 2);
306 
307 					if(sub) {
308 						sub->iExtra++;
309 						sub->iExtra %= 4;
310 
311 						// Change the image
312 						((CImage *)sub->tWidget)->Change(DynDrawFromSurface(gfxGame.bmpTeamColours[sub->iExtra]));
313 
314 						tMenu->sLocalPlayers[changeTeamPlayerId].setTeam(sub->iExtra);
315 						tMenu->sLocalPlayers[changeTeamPlayerId].getProfile()->iTeam = sub->iExtra;
316 					}
317 
318 					tMenu->sLocalPlayers[changeTeamPlayerId].ChangeGraphics(tLXOptions->tGameInfo.gameMode->GeneralGameType());
319 
320 					// Reload the skin
321 					sub = lv->getSubItem(it, 0);
322 					if (sub)  {
323 						sub->bmpImage = tMenu->sLocalPlayers[changeTeamPlayerId].getPicimg();
324 					}
325 				}
326 				break;
327 
328 
329 			// Game type
330 			case ml_Gametype:
331 				if(ev->iEventMsg == CMB_CHANGED) {
332 					tLXOptions->tGameInfo.gameMode = GameMode((GameModeIndex)cLocalMenu.SendMessage(ml_Gametype, CBM_GETCURINDEX, (DWORD)0, 0));
333 
334 					// Go through the items and enable/disable the team flags and update worm graphics
335 					bool teams_on = tLXOptions->tGameInfo.gameMode->GameTeams() > 1;
336 					CListview *lv = (CListview *)cLocalMenu.getWidget(ml_Playing);
337 					lv_item_t *it = lv->getItems();
338 					lv_subitem_t *sub = NULL;
339 					for (; it; it = it->tNext)  {
340 						sub = lv->getSubItem(it, 2);
341 						if (sub)
342 							sub->bVisible = teams_on;
343 
344 						// Update the skin
345 						sub = lv->getSubItem(it, 0);
346 						if (sub)  {
347 							tMenu->sLocalPlayers[it->iIndex].ChangeGraphics(tLXOptions->tGameInfo.gameMode->GeneralGameType());
348 							sub->bmpImage = tMenu->sLocalPlayers[it->iIndex].getPicimg();
349 						}
350 
351 					}
352 				}
353 				break;
354 
355 			// Level list combo box
356 			case ml_LevelList:
357 				if(ev->iEventMsg == CMB_CHANGED) {
358 
359 					Menu_LocalShowMinimap(true);
360 				}
361 				break;
362 
363 
364 			// Game settings button
365 			case ml_GameSettings:
366 				if(ev->iEventMsg == BTN_CLICKED) {
367 
368 					cLocalMenu.Draw( tMenu->bmpBuffer.get() );
369 
370 					bGameSettings = true;
371 					Menu_GameSettings();
372 				}
373 				break;
374 
375 
376             // Weapons Restrictions button
377             case ml_WeaponOptions:
378                 if( ev->iEventMsg == BTN_CLICKED ) {
379 
380 					cLocalMenu.Draw( tMenu->bmpBuffer.get() );
381 
382                     // Get the current mod
383 					cb_item_t *it = (cb_item_t *)cLocalMenu.SendMessage(ml_ModName,CBM_GETCURITEM,(DWORD)0,0); // TODO: 64bit unsafe (pointer cast)
384                     if(it) {
385 
386 					    bWeaponRest = true;
387 					    Menu_WeaponsRestrictions(it->sIndex);
388                     }
389                 }
390                 break;
391 
392 		}
393 	}
394 
395 	// Draw the mouse
396 	DrawCursor(VideoPostProcessor::videoSurface());
397 }
398 
399 //////////////////
400 // Move a worm from player list to playing list
Menu_LocalAddPlaying(int index)401 void Menu_LocalAddPlaying(int index)
402 {
403 	// Add the item to the players list
404 	CListview *lv = (CListview *)cLocalMenu.getWidget(ml_PlayerList);
405 	if (index < 0)
406 		index = lv->getCurIndex();
407 
408 	if(index < 0 || index >= MAX_PLAYERS) {
409 		errors << "Menu_LocalAddPlaying: invalid index = " << index << endl;
410 		return;
411 	}
412 
413 	// Check if we have enough room for another player
414 	if(!Menu_LocalCheckPlaying(index))
415 		return;
416 
417 
418 	// Remove the item from the list
419 	lv->RemoveItem(index);
420 
421 	profile_t *ply = FindProfile(index);
422 
423 	if(!ply)
424 		return;
425 
426 	// Add a player onto the local players list
427 	if (!tMenu->sLocalPlayers[index].isUsed())  {  // If the players persists from previous game, don't reset its team
428 											// and other game details
429 		tMenu->sLocalPlayers[index].setUsed(true);
430 		tMenu->sLocalPlayers[index].setHealth(0);
431 		tMenu->sLocalPlayers[index].setTeam(0);
432 	}
433 
434 	// Reload the graphics in case the gametype has changed
435 	tMenu->sLocalPlayers[index].setProfile(ply);
436 	tMenu->sLocalPlayers[index].setSkin(ply->cSkin);
437 	tMenu->sLocalPlayers[index].ChangeGraphics(tLXOptions->tGameInfo.gameMode->GeneralGameType());
438 
439 
440 	// Add the item
441 	CImage *img = new CImage(gfxGame.bmpTeamColours[tMenu->sLocalPlayers[index].getTeam()]);
442 	if (img)  {
443 		img->setID(index);
444 		img->setRedrawMenu(false);
445 	} else
446 		warnings << "Cannot load teamcolor image" << endl;
447 	lv = (CListview *)cLocalMenu.getWidget(ml_Playing);
448 	lv->AddItem("",index,tLX->clListView);
449 	lv->AddSubitem(LVS_IMAGE, "", tMenu->sLocalPlayers[index].getPicimg(), NULL);
450 	lv->AddSubitem(LVS_TEXT, ply->sName, (DynDrawIntf*)NULL, NULL);
451 	lv->AddSubitem(LVS_WIDGET, "", (DynDrawIntf*)NULL, img);
452 
453 	// If we're in deathmatch, make the team colour invisible
454 	lv_subitem_t *sub = lv->getSubItem(lv->getLastItem(), 2);
455 	if(sub) {
456 		if(tLXOptions->tGameInfo.gameMode->GameTeams() <= 1)
457 			sub->bVisible = false;
458 		sub->iExtra = 0;
459 	} else
460 		warnings << "Strange: did not found teamcolor subitem" << endl;
461 }
462 
463 //////////////////
464 // Move a player from playing list back to player list
Menu_LocalRemovePlaying(int index)465 void Menu_LocalRemovePlaying(int index)
466 {
467 	// Put the player back into the players list
468 	CListview *lv = (CListview *)cLocalMenu.getWidget(ml_Playing);
469 	if (index < 0)
470 		index = lv->getCurIndex();
471 
472 	// Remove the item from the list
473 	lv->RemoveItem(index);
474 	tMenu->sLocalPlayers[index].setUsed(false);
475 
476 	profile_t *ply = FindProfile(index);
477 
478 	// Add the player into the players list
479 	if(ply) {
480 		ply->cSkin.RemoveColorization();
481 		lv = (CListview *)cLocalMenu.getWidget(ml_PlayerList);
482 		lv->AddItem("", index, tLX->clListView);
483 		lv->AddSubitem(LVS_IMAGE, "", ply->cSkin.getPreview(), NULL);
484 		lv->AddSubitem(LVS_TEXT, ply->sName, (DynDrawIntf*)NULL, NULL);
485 	}
486 }
487 
488 
489 ///////////////////
490 // Add the profiles to the players list
Menu_LocalAddProfiles()491 void Menu_LocalAddProfiles()
492 {
493 	profile_t *p = GetProfiles();
494 
495 	for(; p; p=p->tNext) {
496 		cLocalMenu.SendMessage( ml_PlayerList, LVS_ADDITEM, "", p->iID);
497 		//cLocalMenu.SendMessage( ml_PlayerList, LVS_ADDSUBITEM, (DWORD)p->bmpWorm, LVS_IMAGE); // TODO: 64bit unsafe (pointer cast)
498 		//cLocalMenu.SendMessage( ml_PlayerList, LVS_ADDSUBITEM, p->sName, LVS_TEXT);
499 		CListview * w = (CListview *) cLocalMenu.getWidget(ml_PlayerList);
500 		w->AddSubitem( LVS_IMAGE, "", p->cSkin.getPreview(), NULL );
501 		w->AddSubitem( LVS_TEXT, p->sName, (DynDrawIntf*)NULL, NULL );
502 	}
503 
504 	// Add players from previous game to playing list
505 	// TODO: add the players in the same order as last time
506 	// it's a bit annoying if you add 2 human players and they switch always after a game the role
507 	if (tMenu->sLocalPlayers != NULL)  {
508 		for (int i=0; i < MAX_PLAYERS; i++)  {
509 			if (tMenu->sLocalPlayers[i].isUsed())  {
510 				Menu_LocalAddPlaying(i);
511 			}
512 		}
513 	}
514 
515 
516 }
517 
518 
519 ///////////////////
520 // Show the minimap
Menu_LocalShowMinimap(bool bReload)521 void Menu_LocalShowMinimap(bool bReload)
522 {
523 	// TODO: optimize or recode this!
524 	CMap map;
525 	std::string buf;
526 
527 	cLocalMenu.SendMessage(ml_LevelList, CBS_GETCURSINDEX, &buf, 0);
528 
529     //tGameInfo.sMapRandom.bUsed = false;
530 
531 	// Draw a background over the old minimap
532 	//DrawImageAdv(tMenu->bmpBuffer, tMenu->bmpMainBack, 126,132,126,132,128,96);
533 
534 	// Load the map
535     if( bReload ) {
536 		/*
537         // Create a random map
538         if( buf == "_random_" ) {
539             if( map.Create(504,350,map.findRandomTheme(), 128, 96) ) {
540 				map.TileMap();
541 			    map.ApplyRandom();
542 
543                 // Free any old random map object list
544                 if( tGameInfo.sMapRandom.psObjects ) {
545                     delete[] tGameInfo.sMapRandom.psObjects;
546                     tGameInfo.sMapRandom.psObjects = NULL;
547                 }
548 
549                 // Copy the layout
550                 maprandom_t *psRand = map.getRandomLayout();
551                 tGameInfo.sMapRandom = *psRand;
552                 tGameInfo.sMapRandom.bUsed = true;
553 
554                 // Copy the objects, not link
555                 tGameInfo.sMapRandom.psObjects = new object_t[tGameInfo.sMapRandom.nNumObjects];
556                 if( tGameInfo.sMapRandom.psObjects ) {
557                     for( int i=0; i<tGameInfo.sMapRandom.nNumObjects; i++ ) {
558                         tGameInfo.sMapRandom.psObjects[i] = psRand->psObjects[i];
559                     }
560                 }
561 
562                 // Draw the minimap
563 		        DrawImage(tMenu->bmpMiniMapBuffer.get(), map.GetMiniMap(), 0,0);
564 		        map.Shutdown();
565             }
566 
567         } else {
568         */
569 
570 		// Load the file
571 		if(map.Load("levels/" + buf)) {
572 			// Draw the minimap
573 			if(map.GetMiniMap().get())
574 				DrawImage(tMenu->bmpMiniMapBuffer.get(), map.GetMiniMap(), 0,0);
575 			else
576 				DrawRectFill(tMenu->bmpMiniMapBuffer.get(), 0, 0, tMenu->bmpMiniMapBuffer->w, tMenu->bmpMiniMapBuffer->h, Color());
577         }
578     }
579 
580 	// Update the screen
581     DrawImage(tMenu->bmpBuffer.get(), tMenu->bmpMiniMapBuffer, 136,132);
582 	DrawImageAdv(VideoPostProcessor::videoSurface(), tMenu->bmpBuffer, 130,130,130,130,140,110);
583 }
584 
585 
586 ///////////////////
587 // Start a local game
Menu_LocalStartGame()588 void Menu_LocalStartGame()
589 {
590 	// Level
591 	cLocalMenu.SendMessage(ml_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
592 	cLocalMenu.SendMessage(ml_LevelList, CBS_GETCURNAME, &tLXOptions->tGameInfo.sMapName, 0);
593 
594 
595 	//
596 	// Players
597 	//
598 	CListview *lv_playing = (CListview *)cLocalMenu.getWidget(ml_Playing);
599 
600 	if (lv_playing->getItemCount() == 0) {
601 		Menu_MessageBox("Too few players", "You have to select at least one player.");
602 		return;
603 	}
604 
605 	if(lv_playing->getItemCount() > MAX_PLAYERS) {
606 		Menu_MessageBox("Too many players",
607 						"You have selected " + itoa(lv_playing->getItemCount()) + " players "
608 						"but only " + itoa(MAX_PLAYERS) + " players are possible.");
609 		return;
610 	}
611 
612 	tLX->iGameType = GME_LOCAL;
613 
614 	if(! cClient->Initialize() )
615 	{
616 		errors << "Could not initialize client" << endl;
617 		return;
618 	}
619 
620 	if(!cServer->StartServer()) {
621 		errors << "Could not start server" << endl;
622 		return;
623 	}
624 
625     int count = 0;
626 
627     // Add the human players onto the list
628     for(lv_item_t* item = lv_playing->getItems(); item != NULL; item = item->tNext) {
629     	int i = item->iIndex;
630 		if(tMenu->sLocalPlayers[i].isUsed() && tMenu->sLocalPlayers[i].getProfile() && tMenu->sLocalPlayers[i].getProfile()->iType == PRF_HUMAN->toInt()) {
631 			tMenu->sLocalPlayers[i].getProfile()->iTeam = tMenu->sLocalPlayers[i].getTeam();
632 			cClient->getLocalWormProfiles()[count++] = tMenu->sLocalPlayers[i].getProfile();
633         }
634     }
635 
636     // Add the unhuman players onto the list
637     for(lv_item_t* item = lv_playing->getItems(); item != NULL; item = item->tNext) {
638     	int i = item->iIndex;
639 		if(tMenu->sLocalPlayers[i].isUsed() && tMenu->sLocalPlayers[i].getProfile() && tMenu->sLocalPlayers[i].getProfile()->iType != PRF_HUMAN->toInt()) {
640 			tMenu->sLocalPlayers[i].getProfile()->iTeam = tMenu->sLocalPlayers[i].getTeam();
641 			cClient->getLocalWormProfiles()[count++] = tMenu->sLocalPlayers[i].getProfile();
642         }
643     }
644 
645     cClient->setNumWorms(count);
646 
647 	// Can't start a game with no-one playing
648 	if(count == 0)
649 		return;
650 
651 	// Save the current level in the options
652 	cLocalMenu.SendMessage(ml_LevelList, CBS_GETCURSINDEX, &tLXOptions->tGameInfo.sMapFile, 0);
653 
654 	//
655 	// Game Info
656 	//
657 	tLXOptions->tGameInfo.gameMode = GameMode((GameModeIndex)cLocalMenu.SendMessage(ml_Gametype, CBM_GETCURINDEX, (DWORD)0, 0));
658 
659     //tLXOptions->sServerPassword = ""; // TODO: we have set this, why? it overwrites the password which is very annoying
660 
661     // Get the mod name
662 	cb_item_t *it = (cb_item_t *)cLocalMenu.SendMessage(ml_ModName,CBM_GETCURITEM,(DWORD)0,0); // TODO: 64bit unsafe (pointer cast)
663     if(it) {
664         tLXOptions->tGameInfo.sModName = it->sName;
665 		tLXOptions->tGameInfo.sModDir = it->sIndex;
666     } else {
667 
668 		// Couldn't find a mod to load
669 		cLocalMenu.Draw(tMenu->bmpBuffer.get());
670 		Menu_MessageBox("Error","Could not find a mod to load!", LMB_OK);
671 		DrawImage(tMenu->bmpBuffer.get(),tMenu->bmpMainBack_common,0,0);
672         Menu_DrawBox(tMenu->bmpBuffer.get(), 15,130, 625, 465);
673 		Menu_DrawSubTitle(tMenu->bmpBuffer.get(),SUB_LOCAL);
674 		Menu_RedrawMouse(true);
675 		return;
676 	}
677 
678 	*bGame = true;
679 	tMenu->bMenuRunning = false;
680 	tLX->iGameType = GME_LOCAL;
681 
682 	// Tell the client to connect to the server
683 	cClient->Connect("127.0.0.1:" + itoa(cServer->getPort()));
684 
685 	cLocalMenu.Shutdown();
686 }
687 
688 ///////////////////
689 // Check if we can add another player to the list
Menu_LocalCheckPlaying(int index)690 bool Menu_LocalCheckPlaying(int index)
691 {
692 	uint		plycount = 0;
693 	uint		hmncount = 0;
694 	profile_t	*p;
695 	CListview *lv_playing = (CListview *)cLocalMenu.getWidget(ml_Playing);
696 
697 
698 	// Go through the playing list
699     for(lv_item_t* item = lv_playing->getItems(); item != NULL; item = item->tNext) {
700     	int i = item->iIndex;
701         if(!tMenu->sLocalPlayers[i].isUsed())
702             continue;
703 
704 		if(tMenu->sLocalPlayers[i].getProfile()->iType == PRF_HUMAN->toInt())
705 			hmncount++;
706 		plycount++;
707 	}
708 
709 	p = FindProfile(index);
710 
711 	// TODO: make it possible to use more than 2 local players
712 
713 	// Check if there is too many players
714 	if(plycount >= MAX_PLAYERS)
715 		return false;
716 
717 	// Check if there is too many human players (MAX: 2)
718 	if(p) {
719 		if(p->iType == PRF_HUMAN->toInt() && hmncount >= 2)
720 			return false;
721 	}
722 
723 	return true;
724 }
725 
726 
727 	class ModAdder { public:
728 		CCombobox* combobox;
ModAdder(CCombobox * cb_)729 		ModAdder(CCombobox* cb_) : combobox(cb_) {}
operator ()(const std::string & abs_filename)730 		bool operator() (const std::string& abs_filename) {
731 			size_t sep = findLastPathSep(abs_filename);
732 			if(sep != std::string::npos) {
733 				std::string name;
734 				if(CGameScript::CheckFile(abs_filename, name, true))
735 					combobox->addItem(abs_filename.substr(sep+1), name);
736 			}
737 
738 			return true;
739 		}
740 	};
741 
742 
743 ///////////////////
744 // Fill in the mod list
745 // HINT: also used by Menu_Net_Host
746 // TODO: move to MenuSystem
Menu_Local_FillModList(CCombobox * cb)747 void Menu_Local_FillModList( CCombobox *cb )
748 {
749 	// Find all directories in the the lierox
750 	cb->clear();
751 	cb->setSorted(SORT_ASC);
752 	cb->setUnique(true);
753 	ModAdder adder(cb);
754 	FindFiles(adder,"",false,FM_DIR);
755 
756 	cb->setCurSIndexItem(tLXOptions->tGameInfo.sModDir);
757 }
758 
759 }; // namespace DeprecatedGUI
760