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