1 #include "selgame.h"
2
3 #include "all.h"
4 #include "../3rdParty/Storm/Source/storm.h"
5 #include "config.h"
6 #include "DiabloUI/diabloui.h"
7 #include "DiabloUI/text.h"
8 #include "DiabloUI/dialogs.h"
9 #include "DiabloUI/selok.h"
10 #include "DiabloUI/selhero.h"
11 #include "options.h"
12
13 namespace dvl {
14
15 char selgame_Label[32];
16 char selgame_Ip[129] = "";
17 char selgame_Password[16] = "";
18 char selgame_Description[256];
19 bool selgame_enteringGame;
20 int selgame_selectedGame;
21 bool selgame_endMenu;
22 int *gdwPlayerId;
23 int nDifficulty;
24 int nTickRate;
25 int heroLevel;
26
27 static _SNETPROGRAMDATA *m_client_info;
28 extern int provider;
29
30 #define DESCRIPTION_WIDTH 205
31
32 namespace {
33
34 char title[32];
35
36 std::vector<UiListItem *> vecSelGameDlgItems;
37 std::vector<UiItemBase *> vecSelGameDialog;
38
39 } // namespace
40
selgame_FreeVectors()41 void selgame_FreeVectors()
42 {
43 for (std::size_t i = 0; i < vecSelGameDlgItems.size(); i++) {
44 UiListItem *pUIItem = vecSelGameDlgItems[i];
45 delete pUIItem;
46 }
47 vecSelGameDlgItems.clear();
48
49 for (std::size_t i = 0; i < vecSelGameDialog.size(); i++) {
50 UiItemBase *pUIItem = vecSelGameDialog[i];
51 delete pUIItem;
52 }
53 vecSelGameDialog.clear();
54 }
55
selgame_Free()56 void selgame_Free()
57 {
58 ArtBackground.Unload();
59
60 selgame_FreeVectors();
61 }
62
selgame_GameSelection_Init()63 void selgame_GameSelection_Init()
64 {
65 selgame_enteringGame = false;
66 selgame_selectedGame = 0;
67
68 if (provider == SELCONN_LOOPBACK) {
69 selgame_enteringGame = true;
70 selgame_GameSelection_Select(0);
71 return;
72 }
73
74 strcpy(selgame_Ip, sgOptions.Network.szPreviousHost);
75
76 selgame_FreeVectors();
77
78 UiAddBackground(&vecSelGameDialog);
79 UiAddLogo(&vecSelGameDialog);
80
81 SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
82 vecSelGameDialog.push_back(new UiArtText("Client-Server (TCP)", rect1, UIS_CENTER | UIS_BIG));
83
84 SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 };
85 vecSelGameDialog.push_back(new UiArtText("Description:", rect2, UIS_MED));
86
87 SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
88 vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3));
89
90 SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 300), (Sint16)(UI_OFFSET_Y + 211), 295, 33 };
91 vecSelGameDialog.push_back(new UiArtText("Select Action", rect4, UIS_CENTER | UIS_BIG));
92
93 vecSelGameDlgItems.push_back(new UiListItem("Create Game", 0));
94 vecSelGameDlgItems.push_back(new UiListItem("Join Game", 1));
95
96 vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 305, (UI_OFFSET_Y + 255), 285, 26, UIS_CENTER | UIS_MED | UIS_GOLD));
97
98 SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
99 vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
100
101 SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
102 vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
103
104 UiInitList(vecSelGameDlgItems.size(), selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, vecSelGameDialog);
105 }
106
selgame_GameSelection_Focus(int value)107 void selgame_GameSelection_Focus(int value)
108 {
109 switch (vecSelGameDlgItems[value]->m_value) {
110 case 0:
111 strncpy(selgame_Description, "Create a new game with a difficulty setting of your choice.", sizeof(selgame_Description) - 1);
112 break;
113 case 1:
114 strncpy(selgame_Description, "Enter an IP or a hostname and join a game already in progress at that address.", sizeof(selgame_Description) - 1);
115 break;
116 }
117 WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
118 }
119
120 /**
121 * @brief Load the current hero level from save file
122 * @param pInfo Hero info
123 * @return always true
124 */
UpdateHeroLevel(_uiheroinfo * pInfo)125 BOOL UpdateHeroLevel(_uiheroinfo *pInfo)
126 {
127 if (strcasecmp(pInfo->name, gszHero) == 0)
128 heroLevel = pInfo->level;
129
130 return true;
131 }
132
selgame_GameSelection_Select(int value)133 void selgame_GameSelection_Select(int value)
134 {
135 selgame_enteringGame = true;
136 selgame_selectedGame = value;
137
138 gfnHeroInfo(UpdateHeroLevel);
139
140 selgame_FreeVectors();
141
142 UiAddBackground(&vecSelGameDialog);
143 UiAddLogo(&vecSelGameDialog);
144
145 SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
146 vecSelGameDialog.push_back(new UiArtText(title, rect1, UIS_CENTER | UIS_BIG));
147
148 SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 34), (Sint16)(UI_OFFSET_Y + 211), 205, 33 };
149 vecSelGameDialog.push_back(new UiArtText(selgame_Label, rect2, UIS_CENTER | UIS_BIG));
150
151 SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
152 vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3));
153
154 switch (value) {
155 case 0: {
156 strncpy(title, "Create Game", sizeof(title) - 1);
157
158 SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 };
159 vecSelGameDialog.push_back(new UiArtText("Select Difficulty", rect4, UIS_CENTER | UIS_BIG));
160
161 vecSelGameDlgItems.push_back(new UiListItem("Normal", DIFF_NORMAL));
162 vecSelGameDlgItems.push_back(new UiListItem("Nightmare", DIFF_NIGHTMARE));
163 vecSelGameDlgItems.push_back(new UiListItem("Hell", DIFF_HELL));
164
165 vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 282), 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD));
166
167 SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
168 vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
169
170 SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
171 vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
172
173 UiInitList(vecSelGameDlgItems.size(), selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, vecSelGameDialog, true);
174 break;
175 }
176 case 1: {
177 strncpy(title, "Join TCP Games", sizeof(title) - 1);
178
179 SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 };
180 vecSelGameDialog.push_back(new UiArtText("Enter address", rect4, UIS_CENTER | UIS_BIG));
181
182 SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 };
183 vecSelGameDialog.push_back(new UiEdit(selgame_Ip, 128, rect5, UIS_MED | UIS_GOLD));
184
185 SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
186 vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
187
188 SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
189 vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect7, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
190
191 UiInitList(0, NULL, selgame_Password_Init, selgame_GameSelection_Init, vecSelGameDialog);
192 break;
193 }
194 }
195 }
196
selgame_GameSelection_Esc()197 void selgame_GameSelection_Esc()
198 {
199 UiInitList_clear();
200 selgame_enteringGame = false;
201 selgame_endMenu = true;
202 }
203
selgame_Diff_Focus(int value)204 void selgame_Diff_Focus(int value)
205 {
206 switch (vecSelGameDlgItems[value]->m_value) {
207 case DIFF_NORMAL:
208 strncpy(selgame_Label, "Normal", sizeof(selgame_Label) - 1);
209 strncpy(selgame_Description, "Normal Difficulty\nThis is where a starting character should begin the quest to defeat Diablo.", sizeof(selgame_Description) - 1);
210 break;
211 case DIFF_NIGHTMARE:
212 strncpy(selgame_Label, "Nightmare", sizeof(selgame_Label) - 1);
213 strncpy(selgame_Description, "Nightmare Difficulty\nThe denizens of the Labyrinth have been bolstered and will prove to be a greater challenge. This is recommended for experienced characters only.", sizeof(selgame_Description) - 1);
214 break;
215 case DIFF_HELL:
216 strncpy(selgame_Label, "Hell", sizeof(selgame_Label) - 1);
217 strncpy(selgame_Description, "Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm.", sizeof(selgame_Description) - 1);
218 break;
219 }
220 WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
221 }
222
IsDifficultyAllowed(int value)223 bool IsDifficultyAllowed(int value)
224 {
225 if (value == 0 || (value == 1 && heroLevel >= 20) || (value == 2 && heroLevel >= 30)) {
226 return true;
227 }
228
229 selgame_Free();
230
231 if (value == 1)
232 UiSelOkDialog(title, "Your character must reach level 20 before you can enter a multiplayer game of Nightmare difficulty.", false);
233 if (value == 2)
234 UiSelOkDialog(title, "Your character must reach level 30 before you can enter a multiplayer game of Hell difficulty.", false);
235
236 LoadBackgroundArt("ui_art\\selgame.pcx");
237
238 return false;
239 }
240
selgame_Diff_Select(int value)241 void selgame_Diff_Select(int value)
242 {
243 if (selhero_isMultiPlayer && !IsDifficultyAllowed(vecSelGameDlgItems[value]->m_value)) {
244 selgame_GameSelection_Select(0);
245 return;
246 }
247
248 nDifficulty = value;
249
250 if (!selhero_isMultiPlayer) {
251 // This is part of a dangerous hack to enable difficulty selection in single-player.
252 // FIXME: Dialogs should not refer to each other's variables.
253
254 // We're in the selhero loop instead of the selgame one.
255 // Free the selgame data and flag the end of the selhero loop.
256 selhero_endMenu = true;
257
258 // We only call FreeVectors because ArtBackground.Unload()
259 // will be called by selheroFree().
260 selgame_FreeVectors();
261
262 // We must clear the InitList because selhero's loop will perform
263 // one more iteration after this function exits.
264 UiInitList_clear();
265
266 return;
267 }
268
269 selgame_GameSpeedSelection();
270 }
271
selgame_Diff_Esc()272 void selgame_Diff_Esc()
273 {
274 if (!selhero_isMultiPlayer) {
275 selgame_Free();
276
277 selhero_Init();
278 selhero_List_Init();
279 return;
280 }
281
282 if (provider == SELCONN_LOOPBACK) {
283 selgame_GameSelection_Esc();
284 return;
285 }
286
287 selgame_GameSelection_Init();
288 }
289
selgame_GameSpeedSelection()290 void selgame_GameSpeedSelection()
291 {
292 gfnHeroInfo(UpdateHeroLevel);
293
294 selgame_FreeVectors();
295
296 UiAddBackground(&vecSelGameDialog);
297 UiAddLogo(&vecSelGameDialog);
298
299 SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
300 vecSelGameDialog.push_back(new UiArtText("Create Game", rect1, UIS_CENTER | UIS_BIG));
301
302 SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 34), (Sint16)(UI_OFFSET_Y + 211), 205, 33 };
303 vecSelGameDialog.push_back(new UiArtText(selgame_Label, rect2, UIS_CENTER | UIS_BIG));
304
305 SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
306 vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3));
307
308 SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 };
309 vecSelGameDialog.push_back(new UiArtText("Select Game Speed", rect4, UIS_CENTER | UIS_BIG));
310
311 vecSelGameDlgItems.push_back(new UiListItem("Normal", 20));
312 vecSelGameDlgItems.push_back(new UiListItem("Fast", 30));
313 vecSelGameDlgItems.push_back(new UiListItem("Faster", 40));
314 vecSelGameDlgItems.push_back(new UiListItem("Fastest", 50));
315
316 vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 279), 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD));
317
318 SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
319 vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
320
321 SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
322 vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
323
324 UiInitList(vecSelGameDlgItems.size(), selgame_Speed_Focus, selgame_Speed_Select, selgame_Speed_Esc, vecSelGameDialog, true);
325 }
326
selgame_Speed_Focus(int value)327 void selgame_Speed_Focus(int value)
328 {
329 switch (vecSelGameDlgItems[value]->m_value) {
330 case 20:
331 strncpy(selgame_Label, "Normal", sizeof(selgame_Label) - 1);
332 strncpy(selgame_Description, "Normal Speed\nThis is where a starting character should begin the quest to defeat Diablo.", sizeof(selgame_Description) - 1);
333 break;
334 case 30:
335 strncpy(selgame_Label, "Fast", sizeof(selgame_Label) - 1);
336 strncpy(selgame_Description, "Fast Speed\nThe denizens of the Labyrinth have been hastened and will prove to be a greater challenge. This is recommended for experienced characters only.", sizeof(selgame_Description) - 1);
337 break;
338 case 40:
339 strncpy(selgame_Label, "Faster", sizeof(selgame_Label) - 1);
340 strncpy(selgame_Description, "Faster Speed\nMost monsters of the dungeon will seek you out quicker than ever before. Only an experienced champion should try their luck at this speed.", sizeof(selgame_Description) - 1);
341 break;
342 case 50:
343 strncpy(selgame_Label, "Fastest", sizeof(selgame_Label) - 1);
344 strncpy(selgame_Description, "Fastest Speed\nThe minions of the underworld will rush to attack without hesitation. Only a true speed demon should enter at this pace.", sizeof(selgame_Description) - 1);
345 break;
346 }
347 WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH);
348 }
349
selgame_Speed_Esc()350 void selgame_Speed_Esc()
351 {
352 selgame_GameSelection_Select(0);
353 }
354
selgame_Speed_Select(int value)355 void selgame_Speed_Select(int value)
356 {
357 nTickRate = vecSelGameDlgItems[value]->m_value;
358
359 if (provider == SELCONN_LOOPBACK) {
360 selgame_Password_Select(0);
361 return;
362 }
363
364 selgame_Password_Init(0);
365 }
366
selgame_Password_Init(int value)367 void selgame_Password_Init(int value)
368 {
369 memset(&selgame_Password, 0, sizeof(selgame_Password));
370
371 selgame_FreeVectors();
372
373 UiAddBackground(&vecSelGameDialog);
374 UiAddLogo(&vecSelGameDialog);
375
376 SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 };
377 vecSelGameDialog.push_back(new UiArtText("Client-Server (TCP)", rect1, UIS_CENTER | UIS_BIG));
378
379 SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 };
380 vecSelGameDialog.push_back(new UiArtText("Description:", rect2, UIS_MED));
381
382 SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 };
383 vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3));
384
385 SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 };
386 vecSelGameDialog.push_back(new UiArtText("Enter Password", rect4, UIS_CENTER | UIS_BIG));
387
388 SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 };
389 vecSelGameDialog.push_back(new UiEdit(selgame_Password, 15, rect5, UIS_MED | UIS_GOLD));
390
391 SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
392 vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
393
394 SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 };
395 vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect7, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD));
396
397 UiInitList(0, NULL, selgame_Password_Select, selgame_Password_Esc, vecSelGameDialog);
398 }
399
IsGameCompatible(GameData * data)400 static bool IsGameCompatible(GameData *data)
401 {
402 if (data->versionMajor == PROJECT_VERSION_MAJOR
403 && data->versionMinor == PROJECT_VERSION_MINOR
404 && data->versionPatch == PROJECT_VERSION_PATCH
405 && data->programid == GAME_ID) {
406 return IsDifficultyAllowed(data->nDifficulty);
407 }
408
409 selgame_Free();
410
411 if (data->programid != GAME_ID) {
412 UiSelOkDialog(title, "The host is running a different game than you.", false);
413 } else {
414 char msg[64];
415 sprintf(msg, "Your version %s does not match the host %d.%d.%d.", PROJECT_VERSION, PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH);
416
417 UiSelOkDialog(title, msg, false);
418 }
419
420 LoadBackgroundArt("ui_art\\selgame.pcx");
421
422 return false;
423 }
424
selgame_Password_Select(int value)425 void selgame_Password_Select(int value)
426 {
427 if (selgame_selectedGame) {
428 strcpy(sgOptions.Network.szPreviousHost, selgame_Ip);
429 if (SNetJoinGame(selgame_selectedGame, selgame_Ip, selgame_Password, NULL, NULL, gdwPlayerId)) {
430 if (!IsGameCompatible(m_client_info->initdata)) {
431 selgame_GameSelection_Select(1);
432 return;
433 }
434
435 UiInitList_clear();
436 selgame_endMenu = true;
437 } else {
438 selgame_Free();
439 UiSelOkDialog("Multi Player Game", SDL_GetError(), false);
440 LoadBackgroundArt("ui_art\\selgame.pcx");
441 selgame_Password_Init(selgame_selectedGame);
442 }
443 return;
444 }
445
446 GameData *data = m_client_info->initdata;
447 data->nDifficulty = nDifficulty;
448 data->nTickRate = nTickRate;
449 data->bRunInTown = sgOptions.Gameplay.bRunInTown;
450 data->bTheoQuest = sgOptions.Gameplay.bTheoQuest;
451 data->bCowQuest = sgOptions.Gameplay.bCowQuest;
452
453 if (SNetCreateGame(NULL, selgame_Password, NULL, 0, (char *)data, sizeof(GameData), MAX_PLRS, NULL, NULL, gdwPlayerId)) {
454 UiInitList_clear();
455 selgame_endMenu = true;
456 } else {
457 selgame_Free();
458 UiSelOkDialog("Multi Player Game", SDL_GetError(), false);
459 LoadBackgroundArt("ui_art\\selgame.pcx");
460 selgame_Password_Init(0);
461 }
462 }
463
selgame_Password_Esc()464 void selgame_Password_Esc()
465 {
466 if (selgame_selectedGame == 1)
467 selgame_GameSelection_Select(1);
468 else
469 selgame_GameSpeedSelection();
470 }
471
UiSelectGame(int a1,_SNETPROGRAMDATA * client_info,_SNETPLAYERDATA * user_info,_SNETUIDATA * ui_info,_SNETVERSIONDATA * file_info,int * playerId)472 int UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info,
473 _SNETVERSIONDATA *file_info, int *playerId)
474 {
475 gdwPlayerId = playerId;
476 m_client_info = client_info;
477 LoadBackgroundArt("ui_art\\selgame.pcx");
478 selgame_GameSelection_Init();
479
480 selgame_endMenu = false;
481 while (!selgame_endMenu) {
482 UiClearScreen();
483 UiPollAndRender();
484 }
485 selgame_Free();
486
487 return selgame_enteringGame;
488 }
489 } // namespace dvl
490