1 /*
2  * file menu_network.c - user interface for setting up networks games
3  *
4  * $Id: menu_network.c,v 1.62 2006/06/13 11:11:27 fzago Exp $
5  *
6  * Program XBLAST
7  * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2; or (at your option)
12  * any later version
13  *
14  * This program is distributed in the hope that it will be entertaining,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.
21  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "xblast.h"
25 
26 /*
27  * shared data for all menus
28  */
29 
30 /*
31  * local constants
32  */
33 #define ANIME_LENGTH 4
34 
35 /*
36  * local variables
37  */
38 
39 /* server configuration */
40 static char serverName[128];
41 static int serverPort;
42 static char serverGame[48];
43 static CFGGameHost cfgServer;
44 static CFGGameHost cfgServerhis[10];
45 
46 /* host data */
47 static char *hostName[MAX_HOSTS];
48 static unsigned hostComplete[MAX_HOSTS];
49 static MENU_ID hostItem[MAX_HOSTS];
50 /* player data */
51 static const char *playerName[MAX_HOSTS][NUM_LOCAL_PLAYER];
52 static XBBool playerValid[MAX_HOSTS][NUM_LOCAL_PLAYER];
53 static CFGPlayerGraphics playerGfx[MAX_HOSTS][NUM_LOCAL_PLAYER];
54 static const CFGPlayerGraphics *pPlayerGfx[NUM_LOCAL_PLAYER];
55 static BMSpriteAnimation playerAnime[ANIME_LENGTH] = {
56 	SpriteStopDown, SpriteWinner3, SpriteWinner2, SpriteWinner,
57 };
58 
59 /* team data */
60 static int teamMode = 0;
61 static MENU_ID teamItem[MAX_HOSTS][NUM_LOCAL_PLAYER];
62 /* network games */
63 static const XBNetworkGame *networkGame[NUM_SEARCH_ROWS];
64 static XBNetworkGame **networkGamehis = NULL;
65 static MENU_ID networkItem[NUM_SEARCH_ROWS];
66 static XBAtom networkAtom;
67 /* data for central */
68 char title[256];
69 char stat0[256];
70 char stat1[256];
71 char stat2[256];
72 char stat3[256];
73 char stat4[256];
74 XBBool autoCentral2 = XBFalse;
75 
76 /****************************************************
77  * shared functions for client and server wait menu *
78  ****************************************************/
79 
80 static XBBool ButtonRefreshSearchCentral (void *par);
81 
82 /*
83  * free hostnames, only use after ServerInit or ClientInit
84  */
85 static void
ClearHostNames(void)86 ClearHostNames (void)
87 {
88 	int i;
89 	for (i = 0; i < MAX_HOSTS; i++) {
90 		if (NULL != hostName[i]) {
91 			free (hostName[i]);
92 			hostName[i] = NULL;
93 		}
94 	}
95 }								/* ClearHostNames */
96 
97 /*
98  * send a host state request, client or server
99  */
100 static void
SendHostStateReq(unsigned id,unsigned state)101 SendHostStateReq (unsigned id, unsigned state)
102 {
103 	switch (Network_GetType ()) {
104 	case XBNT_Server:
105 		Server_ReceiveHostStateReq (0, id, state);
106 		break;
107 	case XBNT_Client:
108 		Client_SendHostStateReq (id, state);
109 		break;
110 	default:
111 		Dbg_Out ("failed to queue host state request, unsupported network type\n");
112 	}
113 }								/* SendHostStateReq */
114 
115 #ifdef UNNEEDED
116 /*
117  * send a team state request, client or server
118  */
119 static void
SendTeamStateReq(unsigned id,unsigned player,unsigned team)120 SendTeamStateReq (unsigned id, unsigned player, unsigned team)
121 {
122 	switch (Network_GetType ()) {
123 	case XBNT_Server:
124 		Server_ReceiveTeamStateReq (0, id, player, team);
125 		break;
126 	case XBNT_Client:
127 		Client_SendTeamStateReq (id, player, team);
128 		break;
129 	default:
130 		Dbg_Out ("failed to queue team state request, unsupported network type\n");
131 	}
132 }								/* SendTeamStateReq */
133 #endif
134 
135 /*
136  * update display pointer for player sprite
137  */
138 static void
UpdatePlayerDisplay(unsigned id,unsigned player)139 UpdatePlayerDisplay (unsigned id, unsigned player)
140 {
141 	switch (Network_GetTeamState (id, player)) {
142 	case XBTS_Invalid:
143 	case XBTS_Out:
144 		pPlayerGfx[player] = NULL;
145 		break;
146 	default:
147 		pPlayerGfx[player] = &playerGfx[id][player];
148 		break;
149 	}
150 }								/* UpdatePlayerDisplay */
151 
152 #ifdef REQUESTS
153 /* detailed requests info in menu, experimental request handling */
154 
155 /*
156  * team change handler - handle local changes of team states
157  */
158 static XBBool
TeamChangeLocal(unsigned id,unsigned player,XBTeamState * cur)159 TeamChangeLocal (unsigned id, unsigned player, XBTeamState * cur)
160 {
161 	assert (id < MAX_HOSTS);
162 	assert (player < NUM_LOCAL_PLAYER);
163 	/* TODO: filtering, some host states might not be sensible */
164 	switch (Network_GetType ()) {
165 	case XBNT_Server:
166 		*cur = (*cur == NUM_XBTS - 1) ? XBTS_None : *cur + 1;
167 		Server_ReceiveTeamStateReq (0, id, player, *cur);
168 		return XBTrue;
169 	case XBNT_Client:
170 		*cur = (*cur == NUM_XBTS - 1) ? XBTS_None : *cur + 1;
171 		Client_SendTeamStateReq (id, player, *cur);
172 		return XBTrue;
173 	default:
174 		Dbg_Out ("local team change failed, unsupported network type\n");
175 		return XBFalse;
176 	}
177 }								/* TeamChangeLocal */
178 
179 /*
180  * team update handler - handle external changes of team states
181  */
182 static XBBool
TeamStateUpdate(unsigned id,unsigned player,XBTeamState * cur,XBTeamState * req)183 TeamStateUpdate (unsigned id, unsigned player, XBTeamState * cur, XBTeamState * req)
184 {
185 	XBHostState newteam;
186 	XBHostState *newreq;
187 	unsigned i;
188 	XBBool chg = XBFalse;
189 	assert (id < MAX_HOSTS);
190 	assert (player < NUM_LOCAL_PLAYER);
191 	newteam = Network_GetTeamState (id, player);
192 	newreq = Network_GetTeamStateReq (id, player);
193 	/* set team colors for player if teamchange */
194 	if (*cur != newteam) {
195 		*cur = newteam;
196 		switch (newteam) {
197 		case XBTS_None:
198 			playerGfx[id][player].body = playerGfx[id][player].bodySave;
199 			playerGfx[id][player].handsFeet = playerGfx[id][player].handsFeetSave;
200 			break;
201 		default:
202 			playerGfx[id][player].body = teamColors[newteam];
203 			playerGfx[id][player].handsFeet = teamColors[newteam];
204 			break;
205 		}
206 		chg = XBTrue;
207 	}
208 	/* check requests */
209 	for (i = 0; i < MAX_HOSTS; i++) {
210 		if (req[i] != newreq[i]) {
211 			req[i] = newreq[i];
212 			chg = XBTrue;
213 		}
214 	}
215 	return chg;
216 }								/* TeamStateUpdate */
217 
218 /*
219  * handle host state changes - local changes
220  */
221 static XBBool
HostChangeLocal(unsigned id,XBHostState * cur)222 HostChangeLocal (unsigned id, XBHostState * cur)
223 {
224 	assert (id < MAX_HOSTS);
225 	switch (Network_GetType ()) {
226 	case XBNT_Server:
227 		switch (*cur) {
228 		case XBHS_None:
229 			return XBFalse;
230 		case XBHS_Wait:
231 			*cur = XBHS_Out;
232 			break;
233 		case XBHS_Server:
234 			*cur = XBHS_Ready;
235 			break;
236 		case XBHS_In:
237 			*cur = (id == 0) ? XBHS_Server : XBHS_Out;
238 			break;
239 		case XBHS_Out:
240 			*cur = (id == 0) ? XBHS_Server : XBHS_In;
241 			break;
242 		case XBHS_Ready:
243 			*cur = (id == 0) ? XBHS_Server : XBHS_Out;
244 			break;
245 		default:
246 			break;
247 		}
248 		Server_ReceiveHostStateReq (0, id, *cur);
249 		return XBTrue;
250 	case XBNT_Client:
251 		switch (*cur) {
252 		case XBHS_None:
253 			return XBFalse;
254 		case XBHS_Wait:
255 			*cur = XBHS_Out;
256 			break;
257 		case XBHS_Server:
258 			*cur = XBHS_Out;
259 			break;
260 		case XBHS_In:
261 			*cur = (id == Network_LocalHostId ())? XBHS_Ready : XBHS_Out;
262 			break;
263 		case XBHS_Out:
264 			*cur = XBHS_In;
265 			break;
266 		case XBHS_Ready:
267 			*cur = (id == Network_LocalHostId ())? XBHS_In : XBHS_Out;
268 			break;
269 		default:
270 			break;
271 		}
272 		Client_SendHostStateReq (id, *cur);
273 		return XBTrue;
274 	default:
275 		Dbg_Out ("local host change failed, unsupported network type\n");
276 		return XBFalse;
277 	}
278 }								/* HostChangeLocal */
279 
280 /*
281  * handle host state update requests
282  */
283 static XBBool
HostStateUpdate(unsigned id,XBHostState * cur,XBHostState * req,int * ping)284 HostStateUpdate (unsigned id, XBHostState * cur, XBHostState * req, int *ping)
285 {
286 	XBHostState newstate;
287 	XBHostState *newreq;
288 	int newping = -1;
289 	unsigned i;
290 	XBBool chg = XBFalse;
291 	assert (id < MAX_HOSTS);
292 	newping = Network_GetPingTime (id);
293 	newstate = Network_GetHostState (id);
294 	newreq = Network_GetHostStateReq (id);
295 	/* check state change */
296 	if (*cur != newstate) {
297 		*cur = newstate;
298 		chg = XBTrue;
299 	}
300 	/* check ping change */
301 	if (newping != *ping) {
302 		*ping = newping;
303 		chg = XBTrue;
304 	}
305 	/* check requests change */
306 	for (i = 0; i < MAX_HOSTS; i++) {
307 		if (req[i] != newreq[i]) {
308 			req[i] = newreq[i];
309 			chg = XBTrue;
310 		}
311 	}
312 	return chg;
313 }								/* HostStateUpdate  */
314 
315 #else
316 /* classic display and request handling */
317 
318 /*
319  * team change handler - handle local changes of team states
320  */
321 static XBBool
TeamChangeLocal(unsigned id,unsigned player,XBTeamState * cur)322 TeamChangeLocal (unsigned id, unsigned player, XBTeamState * cur)
323 {
324 	assert (id < MAX_HOSTS);
325 	assert (player < NUM_LOCAL_PLAYER);
326 	switch (Network_GetType ()) {
327 	case XBNT_Server:
328 		/* cycle to next team, invalid sets player out */
329 		*cur = (*cur == NUM_XBTS - 1) ? XBTS_None : *cur + 1;
330 		Server_ReceiveTeamStateReq (0, id, player, *cur);
331 		return XBTrue;
332 	default:
333 		/* do not allow team change for clients */
334 		return XBFalse;
335 	}
336 }								/* TeamChangeLocal */
337 
338 /*
339  * team update handler - handle team state receive
340  */
341 static XBBool
TeamStateUpdate(unsigned id,unsigned player,XBTeamState * cur,XBTeamState * req)342 TeamStateUpdate (unsigned id, unsigned player, XBTeamState * cur, XBTeamState * req)
343 {
344 	XBTeamState newteam;
345 	XBTeamState *newreq;
346 	assert (id < MAX_HOSTS);
347 	assert (player < NUM_LOCAL_PLAYER);
348 	/* get team and requests */
349 	newteam = Network_GetTeamState (id, player);
350 	newreq = Network_GetTeamStateReq (id, player);
351 	/* set correct colors for player if team changed */
352 	if (*cur != newteam) {
353 		*cur = newteam;
354 		switch (newteam) {
355 		case XBTS_None:
356 			/* restore original colors */
357 			playerGfx[id][player].body = playerGfx[id][player].bodySave;
358 			playerGfx[id][player].handsFeet = playerGfx[id][player].handsFeetSave;
359 			break;
360 		default:
361 			/* team colors */
362 			playerGfx[id][player].body = teamColors[newteam];
363 			playerGfx[id][player].handsFeet = teamColors[newteam];
364 			break;
365 		}
366 		return XBTrue;
367 	}
368 	return XBFalse;
369 }								/* TeamStateUpdate */
370 
371 /*
372  * handle host state changes - local changes
373  */
374 static XBBool
HostChangeLocal(unsigned id,XBHostState * cur)375 HostChangeLocal (unsigned id, XBHostState * cur)
376 {
377 	assert (id < MAX_HOSTS);
378 	switch (Network_GetType ()) {
379 	case XBNT_Server:
380 		/* server menu */
381 		switch (Network_GetHostState (id)) {
382 		case XBHS_Server:
383 			/* request for host marked as server */
384 			assert (id == 0);
385 			switch (*cur) {
386 			case XBHS_Ready:
387 				*cur = XBHS_None;
388 				break;
389 			default:
390 				*cur = XBHS_Ready;
391 				break;
392 			}
393 			break;
394 		case XBHS_In:
395 			/* request for host marked in */
396 			assert (id > 0);
397 			switch (*cur) {
398 			case XBHS_Out:
399 				*cur = XBHS_None;
400 				break;
401 			default:
402 				*cur = XBHS_Out;
403 				break;
404 			}
405 			break;
406 		case XBHS_Ready:
407 			/* request for host marked ready */
408 			switch (*cur) {
409 			case XBHS_Server:
410 				*cur = XBHS_None;
411 				break;
412 			case XBHS_Out:
413 				*cur = XBHS_None;
414 				break;
415 			default:
416 				*cur = (id == 0) ? XBHS_Server : XBHS_Out;
417 				break;
418 			}
419 			break;
420 		case XBHS_Out:
421 			/* request for host marked out */
422 			assert (id > 0);
423 			switch (*cur) {
424 			case XBHS_In:
425 				*cur = XBHS_None;
426 				break;
427 			default:
428 				*cur = (hostComplete[id] == 0) ? XBHS_In : XBHS_Wait;
429 				break;
430 			}
431 			break;
432 		case XBHS_Wait:
433 			/* request for host marked waiting */
434 			assert (id > 0);
435 			switch (*cur) {
436 			case XBHS_Out:
437 				*cur = XBHS_None;
438 				break;
439 			default:
440 				*cur = XBHS_Out;
441 				break;
442 			}
443 			break;
444 		default:
445 			return XBFalse;
446 		}
447 		Server_ReceiveHostStateReq (0, id, *cur);
448 		return XBTrue;
449 	case XBNT_Client:
450 		if (id == Network_LocalHostId ()) {
451 			/* request for local host item */
452 			switch (Network_GetHostState (id)) {
453 			case XBHS_In:
454 				assert (id > 0);
455 				switch (*cur) {
456 				case XBHS_Ready:
457 					*cur = XBHS_None;
458 					break;
459 				default:
460 					*cur = XBHS_Ready;
461 					break;
462 				}
463 				break;
464 			case XBHS_Ready:
465 				switch (*cur) {
466 				case XBHS_In:
467 					*cur = XBHS_None;
468 					break;
469 				default:
470 					*cur = XBHS_In;
471 					break;
472 				}
473 				break;
474 			case XBHS_Out:
475 				switch (*cur) {
476 				case XBHS_In:
477 					*cur = XBHS_Ready;
478 					break;
479 				case XBHS_Ready:
480 					*cur = XBHS_None;
481 					break;
482 				default:
483 					*cur = XBHS_In;
484 					break;
485 				}
486 				break;
487 			default:
488 				return XBFalse;
489 			}
490 			Client_SendHostStateReq (id, *cur);
491 			return XBTrue;
492 		}
493 		return XBFalse;
494 	default:
495 		Dbg_Out ("local host change failed, unsupported network type\n");
496 		return XBFalse;
497 	}
498 }								/* HostChangeLocal */
499 
500 /*
501  * handle host state update requests
502  */
503 static XBBool
HostStateUpdate(unsigned id,XBHostState * cur,XBHostState * req,int * ping)504 HostStateUpdate (unsigned id, XBHostState * cur, XBHostState * req, int *ping)
505 {
506 	XBHostState newstate;
507 	XBHostState *newreq;
508 	int newping = -1;
509 	unsigned i;
510 	XBBool chg = XBFalse;
511 	assert (id < MAX_HOSTS);
512 	newping = Network_GetPingTime (id);
513 	newstate = Network_GetHostState (id);
514 	newreq = Network_GetHostStateReq (id);
515 	/* check state change */
516 	if (*cur != newstate) {
517 		*cur = newstate;
518 		chg = XBTrue;
519 	}
520 	/* check ping change */
521 	if (newping != *ping) {
522 		*ping = newping;
523 		chg = XBTrue;
524 	}
525 	/* check requests change if necessary */
526 	for (i = 0; i < MAX_HOSTS; i++) {
527 		if (req[i] != newreq[i]) {
528 			req[i] = newreq[i];
529 			chg = XBTrue;
530 		}
531 	}
532 	return chg;
533 }								/* HostStateUpdate  */
534 
535 #endif
536 
537 /*
538  * count valid players for a specific host
539  */
540 static unsigned
CountHostPlayers(unsigned id)541 CountHostPlayers (unsigned id)
542 {
543 	unsigned p, cnt = 0;
544 	assert (id < MAX_HOSTS);
545 	for (p = 0; p < NUM_LOCAL_PLAYER; p++) {
546 		if (playerValid[id][p]) {
547 			cnt += 1;
548 		}
549 	}
550 	return cnt;
551 }								/* CountPlayers */
552 
553 /*
554  * count valid players
555  */
556 static unsigned
CountPlayers(void)557 CountPlayers (void)
558 {
559 	unsigned i, cnt = 0;
560 	for (i = 0; i < MAX_HOSTS; i++) {
561 		cnt += CountHostPlayers (i);
562 	}
563 	return cnt;
564 }								/* CountPlayers */
565 
566 #ifdef UNNEEDED
567 /*
568  * count accepted teams by state only
569  */
570 static unsigned
CountTeamsByState()571 CountTeamsByState ()
572 {
573 	unsigned id, pl, p, t, mask;
574 	mask = 0x00;
575 	for (id = 0; id < MAX_HOSTS; id++) {
576 		if (HostIsIn (id)) {
577 			for (pl = 0; pl < NUM_LOCAL_PLAYER; pl++) {
578 				TeamMaskUpdate (&mask, &p, &t, Network_GetTeamState (id, pl));
579 			}
580 		}
581 	}
582 	assert (t == 0 || p == 0);
583 	return (t + p);
584 }								/* CountTeamsByState */
585 #endif
586 
587 /*
588  * create player graphics in menu for client and server
589  */
590 static void
CreatePlayerItems(void)591 CreatePlayerItems (void)
592 {
593 	int i;
594 	for (i = 0; i < NUM_LOCAL_PLAYER; i++) {
595 		MenuAddPlayer (PLAYER_LEFT (i, NUM_LOCAL_PLAYER), PLAYER_TOP, PLAYER_WIDTH, i,
596 					   pPlayerGfx + i, -ANIME_LENGTH, playerAnime);
597 	}
598 }								/* CreatePlayerItems */
599 
600 /*
601  * team focus handler - focus changed to id(player)
602  */
603 static void
TeamFocus(unsigned id,unsigned player)604 TeamFocus (unsigned id, unsigned player)
605 {
606 	assert (id < MAX_HOSTS);
607 	assert (player < NUM_LOCAL_PLAYER);
608 	memset (pPlayerGfx, 0, sizeof (pPlayerGfx));
609 	UpdatePlayerDisplay (id, player);
610 }								/* TeamFocus */
611 
612 #ifdef SMPF
613 
614 /*
615  * create SMPF team items in menu
616  */
617 static void
CreateTeamItems()618 CreateTeamItems ()
619 {
620 	int client = 0;
621 	int c = MENU_TOP;
622 	int r = MENU_TOP;
623 	int p;
624 	r -= CELL_H;
625 	for (client = 0; client < MAX_PLAYER; client++) {
626 		if (client % 3 == 0) {
627 			c = 5 * CELL_W / 2;
628 			r += CELL_H;
629 		}
630 		else {
631 			c += 4 * CELL_W;
632 		}
633 		for (p = 0; p < 2; p++) {
634 			teamItem[client][p] =
635 				MenuAddTeam (c + 1 * CELL_W, r + (2 + p) * CELL_H / 2, 2 * CELL_W, client, p,
636 							 TeamFocus, TeamChangeLocal, TeamStateUpdate);
637 			if (!playerValid[client][p]) {
638 				MenuSetActive (teamItem[client][p], XBFalse);
639 			}
640 		}
641 	}
642 }								/* CreateTeamItems */
643 
644 /*
645  * create SMPF host items in menu
646  */
647 static void
CreateHostItems(XBBool server)648 CreateHostItems (XBBool server)
649 {
650 	int client = 0;
651 	int c = MENU_TOP;
652 	int r = MENU_TOP;
653 	r -= CELL_H;
654 	for (client = 0; client < MAX_PLAYER; client++) {
655 		if (client % 3 == 0) {
656 			c = 5 * CELL_W / 2;
657 			r += CELL_H;
658 		}
659 		else {
660 			c += 4 * CELL_W;
661 		}
662 		MenuAddTag (c - 2 * CELL_W / 2, r + 2 * CELL_H / 2, 2 * CELL_W, &playerName[client][0]);
663 		MenuAddTag (c - 2 * CELL_W / 2, r + 3 * CELL_H / 2, 2 * CELL_W, &playerName[client][1]);
664 	}
665 	CreateTeamItems ();
666 }								/* CreateHostItems */
667 
668 #else
669 
670 /*
671  * create team items in menu, non-SMPF
672  */
673 static void
CreateTeamItems(void)674 CreateTeamItems (void)
675 {
676 	int x, y;
677 	int client = 0;
678 	int p, c, r = MENU_TOP;
679 	for (y = 0; y < 3; y++) {
680 		c = 3 * CELL_W / 2;
681 		for (x = 0; x < 2; x++) {
682 			/* host */
683 			for (p = 0; p < 2; p++) {
684 				teamItem[client][p] =
685 					MenuAddTeam (c + 2 * CELL_W, r + (2 + p) * CELL_H / 2, 3 * CELL_W, client, p,
686 								 TeamFocus, TeamChangeLocal, TeamStateUpdate);
687 				if (!playerValid[client][p]) {
688 					MenuSetActive (teamItem[client][p], XBFalse);
689 				}
690 			}
691 			client++;
692 			c += 6 * CELL_W;
693 		}
694 		r += 2 * CELL_H;
695 	}
696 }								/* CreateTeamItems */
697 
698 /*
699  * focus changed to host item, non-SMPF
700  */
701 static void
HostFocus(unsigned id)702 HostFocus (unsigned id)
703 {
704 	/* show players on host */
705 	unsigned player;
706 	assert (id < MAX_HOSTS);
707 	memset (pPlayerGfx, 0, sizeof (pPlayerGfx));
708 	for (player = 0; player < NUM_LOCAL_PLAYER; player++) {
709 		UpdatePlayerDisplay (id, player);
710 	}
711 }								/* HostFocus */
712 
713 /*
714  * create host items in menu, non-SMPF
715  */
716 static void
CreateHostItems(XBBool server)717 CreateHostItems (XBBool server)
718 {
719 	int x, y;
720 	unsigned client = 0;
721 	int c, r = MENU_TOP;
722 	for (y = 0; y < MAX_PLAYER / 2; y++) {
723 		c = 3 * CELL_W / 2;
724 		for (x = 0; x < 2; x++) {
725 			hostItem[client] =
726 				MenuAddHost (c + 1 * CELL_W, r, 4 * CELL_W, client, (const char **)hostName,
727 							 HostFocus, HostChangeLocal, HostStateUpdate);
728 			if (CountHostPlayers (client) == 0) {
729 				MenuSetActive (hostItem[client], XBFalse);
730 			}
731 			MenuAddTag (c, r + 2 * CELL_H / 2, 2 * CELL_W, &playerName[client][0]);
732 			MenuAddTag (c, r + 3 * CELL_H / 2, 2 * CELL_W, &playerName[client][1]);
733 			client++;
734 			c += 6 * CELL_W;
735 		}
736 		r += 2 * CELL_H;
737 	}
738 	CreateTeamItems ();
739 }								/* CreateHostItems */
740 
741 #endif
742 
743 /*
744  * handle network event "game config", client or server
745  */
746 static void
HandleGameConfig(unsigned clientID)747 HandleGameConfig (unsigned clientID)
748 {
749 	int i;
750 	CFGGamePlayers cfgPlayers;
751 	assert (clientID < MAX_HOSTS);
752 	Dbg_Out ("host #%u sent game config\n", clientID);
753 	/* free old host name, if necessary */
754 	if (NULL != hostName[clientID]) {
755 		free (hostName[clientID]);
756 	}
757 	/* set host name from Remote Database */
758 	hostName[clientID] = DupString (GetHostName (CT_Remote, LOCALGAMECONFIG (clientID)));
759 	fprintf (stderr, "hostname %u= %s\n", clientID, hostName[clientID]);
760 	/* retrieve config data */
761 	if (RetrieveGamePlayers (CT_Remote, LOCALGAMECONFIG (clientID), &cfgPlayers)) {
762 		Dbg_Out ("expecting %u players at host #%u\n", cfgPlayers.num, clientID);
763 		/* set up completeness check */
764 		hostComplete[clientID] = (1 << 0);
765 		for (i = 0; i < cfgPlayers.num && i < NUM_LOCAL_PLAYER; i++) {
766 			if (ATOM_INVALID == cfgPlayers.player[i]) {
767 				break;
768 			}
769 			hostComplete[clientID] |= (1 << (i + 1));
770 		}
771 		SendHostStateReq (clientID, XBHS_Wait);
772 		MenuSetActive (hostItem[clientID], XBTrue);
773 	}
774 	else {
775 		Dbg_Out ("game config error for host %u\n", clientID);
776 		SendHostStateReq (clientID, XBHS_None);
777 	}
778 }								/* HandleGameConfig */
779 
780 /*
781  * handle network event "player config", client or server
782  */
783 static void
HandlePlayerConfig(unsigned clientID,int player)784 HandlePlayerConfig (unsigned clientID, int player)
785 {
786 	XBAtom playerAtom;
787 	assert (clientID < MAX_HOSTS);
788 	assert (player >= 0);
789 	assert (player < NUM_LOCAL_PLAYER);
790 	/* get player atom */
791 	playerAtom = Network_GetPlayer (clientID, player);
792 	/* host still connected? */
793 	if (playerAtom == ATOM_INVALID) {
794 		Dbg_Out ("player config event ignored for host %u\n", clientID);
795 		return;
796 	}
797 	Dbg_Out ("receiving player config for %u(%u)\n", clientID, player);
798 	/* get player data */
799 	playerName[clientID][player] = GetPlayerName (CT_Remote, playerAtom);
800 	playerValid[clientID][player] = XBTrue;
801 	RetrievePlayerGraphics (CT_Remote, playerAtom, COLOR_INVALID, &playerGfx[clientID][player]);
802 	MenuSetActive (teamItem[clientID][player], XBTrue);
803 	/* check completeness and ping */
804 	hostComplete[clientID] &= ~(1 << (1 + player));
805 	if (0 == hostComplete[clientID]) {
806 		SendHostStateReq (clientID, XBHS_In);
807 	}
808 }								/* HandlePlayerConfig */
809 
810 /*
811  * handle ping event
812  */
813 static void
HandlePing(unsigned clientID)814 HandlePing (unsigned clientID)
815 {
816 	if (1 == hostComplete[clientID]) {
817 		SendHostStateReq (clientID, XBHS_In);
818 	}
819 	hostComplete[clientID] &= ~(1 << 0);
820 }								/* HandlePing */
821 
822 /*
823  * handle network events "disconnected", "error", client or server
824  */
825 static void
HandleShutdown(unsigned clientID)826 HandleShutdown (unsigned clientID)
827 {
828 	int j;
829 	assert (clientID < MAX_HOSTS);
830 	/* clear host entry */
831 	if (NULL != hostName[clientID]) {
832 		free (hostName[clientID]);
833 		hostName[clientID] = NULL;
834 	}
835 	/* clear player data */
836 	memset (playerValid[clientID], 0, sizeof (playerValid[clientID]));
837 	memset (playerName[clientID], 0, sizeof (playerName[clientID]));
838 	/* disable host button */
839 	MenuSetActive (hostItem[clientID], XBFalse);
840 	/* disable team button */
841 	for (j = 0; j < NUM_LOCAL_PLAYER; j++) {
842 		MenuSetActive (teamItem[clientID][j], XBFalse);
843 	}
844 	/* exit menu if server has disconnected */
845 	if (0 == clientID) {
846 		MenuExecFunc (CreateMainMenu, NULL);
847 	}
848 }								/* HandleShutdown */
849 
850 /* prototypes for start button handlers */
851 static XBBool ButtonClientStart (void *par);
852 static XBBool ButtonServerStart (void *par);
853 
854 /*
855  * Handle network event "start game"
856  */
857 static void
HandleStartGame(unsigned clientID)858 HandleStartGame (unsigned clientID)
859 {
860 	assert (clientID < MAX_HOSTS);
861 	if (Network_GetType () == XBNT_Server) {
862 		MenuExecFunc (ButtonServerStart, NULL);
863 	}
864 	else {
865 		SetHostType (XBPH_Client1 + clientID - 1);
866 		MenuExecFunc (ButtonClientStart, NULL);
867 	}
868 }								/* HandleStartGame */
869 
870 /********************
871  * server wait menu *
872  ********************/
873 
874 /*
875  * polling for server wait
876  */
877 static void
PollServerWaitMenu(void * par)878 PollServerWaitMenu (void *par)
879 {
880 	XBNetworkEvent msg;
881 	unsigned clientID;
882 	static char skip = 1;
883 	XBAtom *atom = par;
884 	assert (atom != NULL);
885 
886 	/* check network events */
887 	while (XBNW_None != (msg = Network_GetEvent (&clientID))) {
888 		switch (msg) {
889 		case XBNW_Accepted:
890 			/* client has connected */
891 			break;
892 		case XBNW_GameConfig:
893 			HandleGameConfig (clientID);
894 			break;
895 			/* game config received */
896 		case XBNW_RightPlayerConfig:
897 			HandlePlayerConfig (clientID, 0);
898 			break;
899 			/* player data received */
900 		case XBNW_LeftPlayerConfig:
901 			HandlePlayerConfig (clientID, 1);
902 			break;
903 			/* player data received */
904 		case XBNW_Joy1PlayerConfig:
905 			HandlePlayerConfig (clientID, 2);
906 			break;
907 			/* player data received */
908 		case XBNW_Joy2PlayerConfig:
909 			HandlePlayerConfig (clientID, 3);
910 			break;
911 			/* player data received */
912 		case XBNW_PingReceived:
913 			HandlePing (clientID);
914 			break;
915 			/* received a ping for client */
916 		case XBNW_Disconnected:
917 			HandleShutdown (clientID);
918 			break;
919 			/* one host has disconnected */
920 		case XBNW_Error:
921 			HandleShutdown (clientID);
922 			break;
923 			/* error in connection to host */
924 		case XBNW_StartGame:
925 			HandleStartGame (clientID);
926 			break;
927 			/* start game has been triggered by requests */
928 		default:
929 			/* anything else */
930 			break;
931 		}
932 	}
933 	/* retransmit newgame with current player number */
934 	if (cfgServer.central && (skip++ == 0)) {
935 		Dbg_Out ("players=%u\n", CountPlayers ());
936 		Server_RestartNewGame (CountPlayers () & 0xFF, "");
937 	}
938 }								/* PollNetwork */
939 
940 /*
941  * init display variables for server
942  */
943 static void
ServerInit(void)944 ServerInit (void)
945 {
946 	unsigned player;
947 	CFGGamePlayers cfgGame;
948 	CFGGameSetup cfgSetup;
949 	/* clear all data */
950 	memset (hostName, 0, sizeof (hostName));
951 	memset (hostComplete, 0, sizeof (hostComplete));
952 	memset (playerValid, 0, sizeof (playerValid));
953 	memset (playerGfx, 0, sizeof (playerGfx));
954 	memset (playerName, 0, sizeof (playerName));
955 	/* determine local name for server */
956 	hostName[0] = DupString ("localhost");
957 	/* determine local player */
958 	if (RetrieveGamePlayers (CT_Local, atomServer, &cfgGame)) {
959 		Dbg_Out ("found %u local players\n", cfgGame.num);
960 		assert (cfgGame.num < NUM_LOCAL_PLAYER);
961 		for (player = 0; player < cfgGame.num; player++) {
962 			assert (ATOM_INVALID != cfgGame.player[player]);
963 			RetrievePlayerGraphics (CT_Local, cfgGame.player[player], COLOR_INVALID,
964 									&playerGfx[0][player]);
965 			playerValid[0][player] = XBTrue;
966 			playerName[0][player] = GetPlayerName (CT_Local, cfgGame.player[player]);
967 		}
968 	}
969 	else {
970 		Dbg_Out ("no local players on server!\n");
971 	}
972 
973 	/* determine initial teammode */
974 	RetrieveGameSetup (CT_Remote, atomLocal, &cfgSetup);
975 }								/* ServerInit */
976 
977 /*
978  * start button activated
979  */
980 static XBBool
ButtonServerStart(void * par)981 ButtonServerStart (void *par)
982 {
983 	CFGGame cfg;
984 	unsigned id;
985 	unsigned fail = 0;
986 	unsigned max;
987 	/* get previous server game config */
988 	if (!RetrieveGame (CT_Remote, SERVERGAMECONFIG, &cfg)) {
989 		GUI_ErrorMessage ("error retrieving server game config, please report\n");
990 		return XBFalse;
991 	}
992 	/* try to update to complete game config */
993 	switch (Network_CreateGlobalGameConfig (&cfg)) {
994 	case XBGC_Error:
995 		GUI_ErrorMessage ("error when creating game config, please report\n");
996 		return XBFalse;
997 	case XBGC_SingleTeam:
998 		GUI_ErrorMessage ("Need at least two teams/players!\n");
999 		return XBFalse;
1000 	case XBGC_TooManyPlayers:
1001 		GUI_ErrorMessage ("Too many players, kick some!\n");
1002 		return XBFalse;
1003 	case XBGC_Global:
1004 		for (id = 1; id < MAX_HOSTS; id++) {
1005 			if (Network_HostIsIn (id)) {
1006 				max = Network_HostPlayerMax (id);
1007 				if (max < cfg.players.num) {
1008 #ifndef SMPF
1009 					Server_ReceiveHostStateReq (0, id, XBHS_Out);
1010 #endif
1011 					fprintf (stdout, "host #%u handles at most %u players\n", id, max);
1012 					fail++;
1013 				}
1014 			}
1015 		}
1016 		if (fail > 0) {
1017 			Dbg_Out ("%u hosts fail to handle %u players\n", fail, cfg.players.num);
1018 			GUI_ErrorMessage ("hosts unable to handle all players!\n");
1019 			return XBFalse;
1020 		}
1021 		break;
1022 	default:
1023 		GUI_ErrorMessage ("invalid result of game config, please report\n");
1024 		return XBFalse;
1025 	}
1026 	/* store manually, then receive */
1027 	StoreGamePlayers (CT_Remote, SERVERGAMECONFIG, &cfg.players);
1028 	StoreGameSetup (CT_Remote, SERVERGAMECONFIG, &cfg.setup);
1029 	if (!Server_ReceiveGameConfig (0, NULL)) {
1030 		GUI_ErrorMessage ("error receiving global game config, please report\n");
1031 		return XBFalse;
1032 	}
1033 	/*  success, start */
1034 	Server_SendStart ();
1035 	/* clean up */
1036 	ClearHostNames ();
1037 	MenuClear ();
1038 	return XBTrue;
1039 }								/* ButtonServerStart */
1040 
1041 /*
1042  * disconnect button activated
1043  */
1044 static XBBool
ButtonServerDisconnect(void * par)1045 ButtonServerDisconnect (void *par)
1046 {
1047 	Dbg_Out ("stopping server\n");
1048 	Server_StopListen ();
1049 	Dbg_Out ("disconnecting clients\n");
1050 	Server_SendDisconnectAll ();
1051 	Dbg_Out ("cleaning up\n");
1052 	ClearHostNames ();
1053 	return CreateServerMenu (par);
1054 }								/* ButtonServerDisconnect */
1055 
1056 /*
1057  * kickout button activated
1058  */
1059 static XBBool
ButtonServerKickOut(void * par)1060 ButtonServerKickOut (void *par)
1061 {
1062 	int i;
1063 	/* disconnect unwanted clients  */
1064 	for (i = 1; i < MAX_HOSTS; i++) {
1065 		if (Server_GetHostState (i) == (unsigned)XBHS_Out) {
1066 			Dbg_Out ("kicking host %u\n", i);
1067 			Server_SendDisconnect (i);
1068 		}
1069 	}
1070 	return XBFalse;
1071 }								/* ButtonServerKickOut */
1072 
1073 /*
1074  * build server wait menu
1075  */
1076 static XBBool
CreateServerWaitMenu(void * par)1077 CreateServerWaitMenu (void *par)
1078 {
1079 	XBAtom *atom = par;
1080 
1081 	assert (atom != NULL);
1082 	Dbg_Out ("---- creating server wait menu ---\n");
1083 	/* init server data */
1084 	ServerInit ();
1085 	/* build menu */
1086 	MenuClear ();
1087 	/* poll function */
1088 	MenuAddCyclic (PollServerWaitMenu, par);
1089 	/* build player shapes for menu */
1090 	CreatePlayerItems ();
1091 	/* Title */
1092 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Waiting for Clients");
1093 	MenuAddLabel1 (10, 79, TITLE_WIDTH + 60,
1094 				   "Chat with lamer Rado and others in http://xblast.sf.net/irc/");
1095 	/* build host slots */
1096 	CreateHostItems (XBTrue);
1097 	/* Buttons */
1098 	MenuSetAbort (MenuAddHButton
1099 				  (3 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, _("Disconnect"), ButtonServerDisconnect,
1100 				   par));
1101 	(void)MenuAddHButton (11 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, _("Kick out"), ButtonServerKickOut,
1102 						  par);
1103 	MenuSetDefault (MenuAddHButton
1104 					(19 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, _("Start"), ButtonServerStart, NULL));
1105 	/* directional item linking */
1106 	MenuSetLinks ();
1107 	/* that's all */
1108 	return XBFalse;
1109 }								/* CreateServerWaitMenu */
1110 
1111 /********************
1112  * client wait menu *
1113  ********************/
1114 
1115 /*
1116  * polling for server wait
1117  */
1118 static void
PollClientWaitMenu(void * par)1119 PollClientWaitMenu (void *par)
1120 {
1121 	XBNetworkEvent msg;
1122 	unsigned clientID;
1123 	static char skip = 1;
1124 	XBAtom *atom = par;
1125 	assert (atom != NULL);
1126 
1127 	/* check network events */
1128 	while (XBNW_None != (msg = Network_GetEvent (&clientID))) {
1129 		switch (msg) {
1130 		case XBNW_GameConfig:
1131 			HandleGameConfig (clientID);
1132 			break;
1133 			/* game config received */
1134 		case XBNW_RightPlayerConfig:
1135 			HandlePlayerConfig (clientID, 0);
1136 			break;
1137 			/* player data received */
1138 		case XBNW_LeftPlayerConfig:
1139 			HandlePlayerConfig (clientID, 1);
1140 			break;
1141 			/* player data received */
1142 		case XBNW_Joy1PlayerConfig:
1143 			HandlePlayerConfig (clientID, 2);
1144 			break;
1145 			/* player data received */
1146 		case XBNW_Joy2PlayerConfig:
1147 			HandlePlayerConfig (clientID, 3);
1148 			break;
1149 			/* player data received */
1150 		case XBNW_Disconnected:
1151 			HandleShutdown (clientID);
1152 			break;
1153 			/* one host has disconnected */
1154 		case XBNW_Error:
1155 			HandleShutdown (clientID);
1156 			break;
1157 			/* received start game */
1158 		case XBNW_StartGame:
1159 			HandleStartGame (clientID);
1160 			break;
1161 			/* error in connection to host */
1162 		default:
1163 			/* anything else */
1164 			break;
1165 		}
1166 	}
1167 	/* retransmit newgame with current player number */
1168 	if (cfgServer.central && (skip++ == 0)) {
1169 		Dbg_Network ("players=%u\n", CountPlayers ());
1170 		Server_RestartNewGame (CountPlayers () & 0xFF, "");
1171 	}
1172 }								/* PollNetwork */
1173 
1174 /*
1175  * init display variables for client
1176  */
1177 static void
ClientInit(void)1178 ClientInit (void)
1179 {
1180 	/* clear all data */
1181 	memset (hostName, 0, sizeof (hostName));
1182 	memset (hostComplete, 0, sizeof (hostComplete));
1183 	memset (playerValid, 0, sizeof (playerValid));
1184 	memset (playerGfx, 0, sizeof (playerGfx));
1185 	memset (playerName, 0, sizeof (playerName));
1186 }								/* ClientInit */
1187 
1188 /*
1189  * start network game as client
1190  */
1191 static XBBool
ButtonClientStart(void * par)1192 ButtonClientStart (void *par)
1193 {
1194 	ClearHostNames ();
1195 	/* clean up */
1196 	MenuClear ();
1197 	return XBTrue;
1198 }								/* ButtonClientStart */
1199 
1200 /*
1201  * disconnect button activated
1202  */
1203 static XBBool
ButtonClientDisconnect(void * par)1204 ButtonClientDisconnect (void *par)
1205 {
1206 	Dbg_Out ("disconnecting from server\n");
1207 	Client_Disconnect ();
1208 	/* back to connection menu */
1209 	return CreateJoinNetGameMenu (par);
1210 }								/* ButtonDisconnect */
1211 
1212 /*
1213  * build client wait menu
1214  */
1215 static XBBool
CreateClientWaitMenu(void * par)1216 CreateClientWaitMenu (void *par)
1217 {
1218 	XBAtom *atom = par;
1219 	assert (atom != NULL);
1220 	/* needed inits */
1221 	ClientInit ();
1222 	/* build menu */
1223 	MenuClear ();
1224 	/* poll function */
1225 	MenuAddCyclic (PollClientWaitMenu, par);
1226 	/* players */
1227 	CreatePlayerItems ();
1228 	/* Title */
1229 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Game Setup by Server");
1230 	/* hosts */
1231 	teamMode = 0;
1232 	CreateHostItems (XBFalse);
1233 	MenuAddLabel1 (10, 79, TITLE_WIDTH + 60,
1234 				   _("Chat with lamer Rado and others in http://xblast.sf.net/irc/"));
1235 	/* Buttons */
1236 	MenuSetAbort (MenuAddHButton
1237 				  (3 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, _("Disconnect"), ButtonClientDisconnect,
1238 				   par));
1239 	/* --- */
1240 	MenuSetLinks ();
1241 	/* that's all */
1242 	return XBFalse;
1243 }								/* CreateClientWaitMenu */
1244 
1245 /*********************
1246  * server setup menu *
1247  *********************/
1248 
1249 /*
1250  * start the server
1251  */
1252 static XBBool
ButtonServerListen(void * par)1253 ButtonServerListen (void *par)
1254 {
1255 	XBAtom *atom = par;
1256 
1257 	assert (atom != NULL);
1258 	/* set server connection */
1259 	cfgServer.name = NULL;
1260 	cfgServer.port = serverPort;
1261 	cfgServer.game = serverGame;
1262 	/* store in database */
1263 	StoreGameHost (CT_Local, *atom, &cfgServer);
1264 	/* get game setup */
1265 	/* now try connection */
1266 	if (!Server_StartListen (&cfgServer)) {
1267 		/* connection failed */
1268 		GUI_ErrorMessage ("Failed to listen on port %hu", serverPort);
1269 		return CreateServerMenu (par);
1270 	}
1271 	return CreateServerWaitMenu (par);
1272 }								/* ButtonServerListen */
1273 
1274 /*
1275  * back button activated
1276  */
1277 static XBBool
ButtonServerBack(void * par)1278 ButtonServerBack (void *par)
1279 {
1280 	return CreateStartNetGameMenu (par);
1281 }								/* ButtonServerBack */
1282 
1283 /*
1284  * setup xblast server
1285  */
1286 XBBool
CreateServerMenu(void * par)1287 CreateServerMenu (void *par)
1288 {
1289 	XBAtom *atom = par;
1290 
1291 	assert (atom != NULL);
1292 	/* get old server from database */
1293 	if (!RetrieveGameHost (CT_Local, *atom, &cfgServer)) {
1294 		serverPort = 16168;
1295 		serverGame[0] = 0;
1296 	}
1297 	else {
1298 		serverPort = cfgServer.port;
1299 		strncpy (serverGame, cfgServer.game, sizeof (serverGame));
1300 		serverGame[sizeof (serverGame) - 1] = 0;
1301 	}
1302 	/* build menu */
1303 	MenuClear ();
1304 	/* Title */
1305 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Setup Server");
1306 	/* parameters */
1307 	MenuAddInteger (DLG_LEFT, MENU_ROW (0), DLG_WIDTH, "TCP-Port:", 2 * CELL_W, &serverPort, 4096,
1308 					65535);
1309 	MenuAddComboBool (DLG_LEFT, MENU_ROW (1), DLG_WIDTH, "Use fixed UDP-ports", 2 * CELL_W,
1310 					  &cfgServer.fixedUdpPort);
1311 	MenuAddComboBool (DLG_LEFT, MENU_ROW (2), DLG_WIDTH, "Allow clients using NAT", 2 * CELL_W,
1312 					  &cfgServer.allowNat);
1313 	MenuAddComboBool (DLG_LEFT, MENU_ROW (3), DLG_WIDTH, "Visible in LAN:", 2 * CELL_W,
1314 					  &cfgServer.browseLan);
1315 	MenuAddComboBool (DLG_LEFT, MENU_ROW (4), DLG_WIDTH, "Visible in central:", 2 * CELL_W, &cfgServer.central);	// XBCC
1316 	MenuAddString (DLG_LEFT, MENU_ROW (5), DLG_WIDTH, "Name:", 4 * CELL_W, serverGame,
1317 				   sizeof (serverGame));
1318 	MenuAddComboBool (DLG_LEFT, MENU_ROW (6), DLG_WIDTH, "Beep for new clients:", 2 * CELL_W,
1319 					  &cfgServer.beep);
1320 	/* Buttons */
1321 	MenuSetAbort (MenuAddHButton
1322 				  (5 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonServerBack, par));
1323 	MenuSetDefault (MenuAddHButton
1324 					(17 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Continue", ButtonServerListen,
1325 					 par));
1326 	/* --- */
1327 	MenuSetLinks ();
1328 	/* that's all */
1329 	return XBFalse;
1330 }								/* CreateServerMenu */
1331 
1332 /*********************
1333  * central wait menu *
1334  *********************/
1335 
1336 /* forward declaration */
1337 static XBBool CreateCentralWaitMenu (void *par);
1338 
1339 /*
1340  * stop button activated
1341  */
1342 static XBBool
ButtonCentralStop(void * par)1343 ButtonCentralStop (void *par)
1344 {
1345 	/* finish communication to server */
1346 	Central_StopListen ();
1347 	/* finish communication with clients */
1348 	Central_QueueDisconnectAll ();
1349 	/* back to connection menu */
1350 	return CreateCentralMenu (par);
1351 }								/* ButtonDisconnect */
1352 
1353 /*
1354  * update button activated
1355  */
1356 static XBBool
ButtonCentralUpdate(void * par)1357 ButtonCentralUpdate (void *par)
1358 {
1359 	return CreateCentralWaitMenu (par);
1360 }								/* ButtonCentralUpdate */
1361 
1362 /*
1363  * poll function for central
1364  */
1365 static void
PollCentral(void * par)1366 PollCentral (void *par)
1367 {
1368 	static char i = 0;
1369 	XBAtom *atom = par;
1370 	assert (atom != NULL);
1371 	/* clear old games every 256th time */
1372 	if (i++ == 0) {
1373 		C2B_ClearOldGames ();
1374 	}
1375 }								/* PollCentral */
1376 
1377 /*
1378  * build central wait menu
1379  */
1380 static XBBool
CreateCentralWaitMenu(void * par)1381 CreateCentralWaitMenu (void *par)
1382 {
1383 	XBAtom *atom = par;
1384 	int nPlayers = 0, nGames = 0, nGamesPlayed = 0, nTotalGames = 0, nLogins = 0;
1385 	Central_GetStatistics (&nPlayers, &nGames, &nGamesPlayed, &nTotalGames, &nLogins);
1386 	assert (atom != NULL);
1387 	MenuClear ();
1388 	/* poll function */
1389 	MenuAddCyclic (PollCentral, par);	// func has to be void mi_tool.h:46
1390 	/* Title */
1391 	sprintf (title, "Central: %s", serverGame);
1392 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, title);
1393 
1394 	sprintf (stat0, "Number of known players: %i", nPlayers);
1395 	MenuAddLabel (5 * CELL_W / 2, MENU_ROW (1), 10 * CELL_W, stat0);
1396 
1397 	sprintf (stat1, "Number of open games: %i", nGames);
1398 	MenuAddLabel (5 * CELL_W / 2, MENU_ROW (2), 10 * CELL_W, stat1);
1399 
1400 	sprintf (stat2, "Number of played games: %i", nGamesPlayed);
1401 	MenuAddLabel (5 * CELL_W / 2, MENU_ROW (3), 10 * CELL_W, stat2);
1402 
1403 	sprintf (stat3, "Total number of games played: %i", nTotalGames);
1404 	MenuAddLabel (5 * CELL_W / 2, MENU_ROW (4), 10 * CELL_W, stat3);
1405 
1406 	sprintf (stat4, "Total number of logins: %i", nLogins);
1407 	MenuAddLabel (5 * CELL_W / 2, MENU_ROW (5), 10 * CELL_W, stat4);
1408 	/* Buttons */
1409 	MenuSetDefault (MenuAddHButton
1410 					(16 * CELL_W / 2, MENU_BOTTOM, 5 * CELL_W, "Update now", ButtonCentralUpdate,
1411 					 par));
1412 	MenuSetAbort (MenuAddHButton
1413 				  (4 * CELL_W / 2, MENU_BOTTOM, 5 * CELL_W, "Stop", ButtonCentralStop, par));
1414 	/* --- */
1415 	MenuSetLinks ();
1416 	/* that's all */
1417 	return XBFalse;
1418 }								/* CreateClientWaitMenu */
1419 
1420 /**********************
1421  * setup central menu *
1422  **********************/
1423 
1424 /*
1425  * setup central connection XBCC
1426  * used in menu_game.c, why ??
1427  */
1428 void
setAutoCentral2(XBBool set)1429 setAutoCentral2 (XBBool set)
1430 {
1431 	autoCentral2 = set;
1432 }								/* setAutoCentral2 */
1433 
1434 /*
1435  * start central button activated
1436  */
1437 static XBBool
ButtonCentralListen(void * par)1438 ButtonCentralListen (void *par)
1439 {
1440 	XBAtom *atom = par;
1441 
1442 	assert (atom != NULL);
1443 	/* set server connection */
1444 	cfgServer.name = NULL;
1445 	cfgServer.port = serverPort;
1446 	cfgServer.game = serverGame;
1447 	/* store in database */
1448 	StoreGameHost (CT_Local, *atom, &cfgServer);
1449 	/* get game setup */
1450 	/* now try connection */
1451 	if (!Central_StartListen (&cfgServer)) {
1452 		/* connection failed */
1453 		GUI_ErrorMessage ("Failed to listen on port %hu", serverPort);
1454 		return CreateCentralMenu (par);
1455 	}
1456 	return CreateCentralWaitMenu (par);
1457 }								/* ButtonServerListen */
1458 
1459 /*
1460  * back button activated
1461  */
1462 static XBBool
ButtonMainMenu(void * par)1463 ButtonMainMenu (void *par)
1464 {
1465 	/* call main menu */
1466 	return CreateMainMenu (par);
1467 }								/* ButtonMainMenu */
1468 
1469 /*
1470  * build setup central menu
1471  */
1472 XBBool
CreateCentralMenu(void * par)1473 CreateCentralMenu (void *par)
1474 {
1475 	XBAtom *atom = par;
1476 
1477 	assert (atom != NULL);
1478 	/* get old server from database */
1479 	if (!RetrieveGameHost (CT_Local, *atom, &cfgServer)) {
1480 		serverGame[0] = 0;
1481 		serverPort = 16168;
1482 	}
1483 	else {
1484 		strncpy (serverGame, cfgServer.game, sizeof (serverGame));
1485 		serverGame[sizeof (serverGame) - 1] = 0;
1486 		serverPort = cfgServer.port;
1487 	}
1488 	if (autoCentral2) {
1489 		return ButtonCentralListen (par);
1490 	}
1491 	else {
1492 		/* build menu */
1493 		MenuClear ();
1494 		/* Title */
1495 		MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Create a central");
1496 		/* parameters */
1497 		MenuAddString (DLG_LEFT, MENU_ROW (0), DLG_WIDTH, "Central name:", 4 * CELL_W, serverGame,
1498 					   sizeof (serverGame));
1499 		MenuAddInteger (DLG_LEFT, MENU_ROW (1), DLG_WIDTH, "TCP-Port:", 4 * CELL_W, &serverPort,
1500 						4096, 65535);
1501 		/* Buttons */
1502 		MenuSetAbort (MenuAddHButton
1503 					  (5 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonMainMenu, par));
1504 		MenuSetDefault (MenuAddHButton
1505 						(17 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Start", ButtonCentralListen,
1506 						 par));
1507 		/* --- */
1508 		MenuSetLinks ();
1509 		/* that's all */
1510 		return XBFalse;
1511 	}
1512 }								/* CreateCentralMenu */
1513 
1514 /*******************
1515  * ip history menu *
1516  *******************/
1517 
1518 XBBool CreateHistoryNetGameMenu (void *par);
1519 
1520 /*
1521  * reset history data
1522  */
1523 static void
ResetHistoryData(void)1524 ResetHistoryData (void)
1525 {
1526 	int i;
1527 	/* check if something to do */
1528 	if (networkGamehis == NULL) {
1529 		return;
1530 	}
1531 	/* free network games */
1532 	for (i = 0; i < NUM_SEARCH_ROWS; i++) {
1533 		if (networkGamehis[i] != NULL) {
1534 			free (networkGamehis[i]);
1535 			networkGamehis[i] = NULL;
1536 		}
1537 	}
1538 	/* free pointer list */
1539 	free (networkGamehis);
1540 	networkGamehis = NULL;
1541 }								/* ResetHistoryData */
1542 
1543 /*
1544  * history entry activated
1545  */
1546 static XBBool
ButtonStartLanGamehis(void * par)1547 ButtonStartLanGamehis (void *par)
1548 {
1549 	const XBNetworkGame **ptr = par;
1550 	XBBool connect;
1551 	assert (NULL != ptr);
1552 	/* check if entry data is valid */
1553 	if (NULL == *ptr) {
1554 		return XBFalse;
1555 	}
1556 	/* get server connection */
1557 	cfgServer.name = (*ptr)->host;
1558 	cfgServer.port = (*ptr)->port;
1559 	/* store in database */
1560 	StoreGameHost (CT_Local, networkAtom, &cfgServer);
1561 	/* now try connection */
1562 	connect = Client_Connect (&cfgServer);
1563 	if (!connect) {
1564 		/* connection failed */
1565 		GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort);
1566 		return CreateHistoryNetGameMenu (&networkAtom);
1567 	}
1568 	/* clean up */
1569 	ResetHistoryData ();
1570 	/* eter client wait menu */
1571 	return CreateClientWaitMenu (&networkAtom);
1572 }								/* ButtonStartLanGamehis */
1573 
1574 /*
1575  * back button activated
1576  */
1577 static XBBool
ButtonBackLanGamehis(void * par)1578 ButtonBackLanGamehis (void *par)
1579 {
1580 	/* clean up */
1581 	ResetHistoryData ();
1582 	/* back to join menu */
1583 	return CreateJoinNetGameMenu (par);
1584 }								/* ButtonBackLanGamehis */
1585 
1586 /*
1587  * build history menu
1588  */
1589 XBBool
CreateHistoryNetGameMenu(void * par)1590 CreateHistoryNetGameMenu (void *par)
1591 {
1592 	XBAtom *atom = par;
1593 	int i;
1594 	assert (NULL != atom);
1595 	networkAtom = *atom;
1596 	/* reset network ip data */
1597 	ResetHistoryData ();
1598 	/* get ip history */
1599 	if (RetrieveIpHistory (cfgServerhis, networkAtom) == XBFalse) {
1600 		fprintf (stderr, "failed to find history data!\n");
1601 		return XBFalse;
1602 	}
1603 	/* allocate pointer memory for each row */
1604 	networkGamehis = calloc (NUM_SEARCH_ROWS, sizeof (*networkGame));
1605 	assert (networkGamehis != NULL);
1606 	for (i = 0; i < NUM_SEARCH_ROWS && i < 10 && cfgServerhis[i].name != NULL; i++) {
1607 		/* allocate network game struct for each valid row */
1608 		networkGamehis[i] = malloc (sizeof (networkGame));
1609 		assert (networkGamehis[i] != NULL);
1610 		networkGamehis[i]->port = cfgServerhis[i].port;
1611 		networkGamehis[i]->host = (char *)cfgServerhis[i].name;
1612 		networkGamehis[i]->game = "connect";
1613 		networkGamehis[i]->version = "???";
1614 		networkGamehis[i]->ping = 1;
1615 		networkGamehis[i]->numLives = 1;
1616 		networkGamehis[i]->numWins = 1;
1617 		networkGamehis[i]->frameRate = 1;
1618 	}
1619 	MenuClear ();
1620 	/* Title */
1621 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "History Ips");
1622 	/* list of games */
1623 	MenuSetActive (MenuAddGameHeader (SEARCH_LEFT, SEARCH_TOP, SEARCH_WIDTH), XBFalse);
1624 	for (i = 0; i < 10 && networkGamehis[i] != NULL; i++) {
1625 		networkItem[i] =
1626 			MenuAddGameEntry (SEARCH_LEFT, SEARCH_ROW (i), SEARCH_WIDTH,
1627 							  (const XBNetworkGame **)(networkGamehis) + i, ButtonStartLanGamehis);
1628 		MenuSetActive (networkItem[i], XBTrue);
1629 	}
1630 	/* Buttons */
1631 	MenuSetAbort (MenuAddHButton
1632 				  (5 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonBackLanGamehis, par));
1633 	MenuSetLinks ();			// should work infinite loop ??
1634 	/* that's all */
1635 	return XBFalse;
1636 }								/* CreateHistoryNetGameMenu */
1637 
1638 /***********************
1639  * client connect menu *
1640  ***********************/
1641 
1642 /*
1643  * connect button activated
1644  */
1645 static XBBool
ButtonClientConnect(void * par)1646 ButtonClientConnect (void *par)
1647 {
1648 	XBAtom *atom = par;
1649 
1650 	assert (atom != NULL);
1651 	/* get server connection */
1652 	cfgServer.name = serverName;
1653 	cfgServer.port = serverPort;
1654 	/* store in database */
1655 	StoreIpHistory (&cfgServer, *atom);
1656 	StoreGameHost (CT_Local, *atom, &cfgServer);
1657 	/* now try connection */
1658 	if (!Client_Connect (&cfgServer)) {
1659 		/* connection failed */
1660 		GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort);
1661 		return CreateClientMenu (par);
1662 	}
1663 	return CreateClientWaitMenu (par);
1664 }								/* ButtonClientConnect */
1665 
1666 /*
1667  * history button activated
1668  */
1669 static XBBool
ButtonClientHistory(void * par)1670 ButtonClientHistory (void *par)
1671 {
1672 	return CreateHistoryNetGameMenu (par);
1673 }								/* ButtonClientHistory */
1674 
1675 /*
1676  * history button activated
1677  */
1678 static XBBool
ButtonClientBack(void * par)1679 ButtonClientBack (void *par)
1680 {
1681 	return CreateJoinNetGameMenu (par);
1682 }								/* ButtonClientBack */
1683 
1684 /*
1685  * setup connection to server
1686  */
1687 XBBool
CreateClientMenu(void * par)1688 CreateClientMenu (void *par)
1689 {
1690 	XBAtom *atom = par;
1691 	assert (atom != NULL);
1692 	/* get old server from database */
1693 	if (!RetrieveGameHost (CT_Local, *atom, &cfgServer)) {
1694 		serverName[0] = 0;
1695 		serverPort = 16168;
1696 	}
1697 	else {
1698 		strncpy (serverName, cfgServer.name, sizeof (serverName));
1699 		serverName[sizeof (hostName) - 1] = 0;
1700 		serverPort = cfgServer.port;
1701 	}
1702 	/* build menu */
1703 	MenuClear ();
1704 	/* Title */
1705 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Connect to Server");
1706 	/* parameters */
1707 	MenuAddString (DLG_LEFT, MENU_ROW (0), DLG_WIDTH, "Hostname:", 4 * CELL_W, serverName,
1708 				   sizeof (serverName));
1709 	MenuAddInteger (DLG_LEFT, MENU_ROW (1), DLG_WIDTH, "TCP-Port:", 4 * CELL_W, &serverPort, 4096,
1710 					65535);
1711 	/* Buttons */
1712 	MenuSetAbort (MenuAddHButton
1713 				  (3 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonClientBack, par));
1714 	MenuAddHButton (11 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "History", ButtonClientHistory, par);
1715 	MenuSetDefault (MenuAddHButton
1716 					(19 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Connect", ButtonClientConnect,
1717 					 par));
1718 	/* --- */
1719 	MenuSetLinks ();
1720 	/* that's all */
1721 	return XBFalse;
1722 }								/* CreateClientMenu */
1723 
1724 /****************
1725  * search menus *
1726  ****************/
1727 
1728 /*
1729  * poll incoming network games - for all search menus
1730  */
1731 static void
PollNetworkGame(void * par)1732 PollNetworkGame (void *par)
1733 {
1734 	unsigned gameID;
1735 	XBNetworkEvent msg;
1736 
1737 #ifdef W32
1738 #else
1739 	static struct timeval old;
1740 	struct timeval tv;
1741 	gettimeofday (&tv, NULL);
1742 	if (tv.tv_sec - old.tv_sec >= 10) {
1743 		ButtonRefreshSearchCentral (NULL);
1744 		old = tv;
1745 	}
1746 #endif
1747 	while (XBNW_None != (msg = Network_GetEvent (&gameID))) {
1748 		if (msg == XBNW_NetworkGame) {
1749 			const XBNetworkGame *game = Client_NextNetworkGame ();
1750 			if (gameID < NUM_SEARCH_ROWS) {
1751 				networkGame[gameID] = game;
1752 				MenuSetActive (networkItem[gameID], ((NULL != game) && (game->frameRate != 0)
1753 													 && (game->frameRate != 255)));
1754 			}
1755 		}
1756 	}
1757 }								/* PollNetworkGame */
1758 
1759 /*******************
1760  * search LAN menu *
1761  *******************/
1762 
1763 /*
1764  * LAN entry activated
1765  */
1766 static XBBool
ButtonStartLanGame(void * par)1767 ButtonStartLanGame (void *par)
1768 {
1769 	const XBNetworkGame **ptr = par;
1770 	XBBool connect;
1771 
1772 	assert (NULL != ptr);
1773 	if (NULL == *ptr) {
1774 		return XBFalse;
1775 	}
1776 
1777 	/* get server connection */
1778 	cfgServer.name = (*ptr)->host;
1779 	cfgServer.port = (*ptr)->port;
1780 	/* store in database */
1781 	StoreGameHost (CT_Local, networkAtom, &cfgServer);
1782 	/* now try connection */
1783 	connect = Client_Connect (&cfgServer);
1784 	/* clean up */
1785 	Client_StopQuery ();
1786 	memset (networkGame, 0, sizeof (networkGame));
1787 	if (!connect) {
1788 		/* connection failed */
1789 		GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort);
1790 		return CreateSearchLanMenu (&networkAtom);
1791 	}
1792 
1793 	return CreateClientWaitMenu (&networkAtom);
1794 }								/* ButtonStartLanGame */
1795 
1796 /*
1797  * refresh button activated
1798  */
1799 static XBBool
ButtonRefreshSearchLan(void * par)1800 ButtonRefreshSearchLan (void *par)
1801 {
1802 	unsigned i;
1803 
1804 	/* delete old games */
1805 	teamMode = 0;
1806 	memset (networkGame, 0, sizeof (networkGame));
1807 	for (i = 0; i < NUM_SEARCH_ROWS; i++) {
1808 		MenuSetActive (networkItem[i], XBFalse);
1809 	}
1810 	/* starts new query */
1811 	Client_RestartQuery ();
1812 	return XBFalse;
1813 }								/* ButtonRefreshSearchLam */
1814 
1815 /*
1816  * exit button activated
1817  */
1818 static XBBool
ButtonExitSearchLan(void * par)1819 ButtonExitSearchLan (void *par)
1820 {
1821 	/* stop network search */
1822 	Client_StopQuery ();
1823 	teamMode = 0;
1824 	/* back to client menu */
1825 	return CreateJoinNetGameMenu (par);
1826 }								/* ButtonExitSearchLan */
1827 
1828 /*
1829  * build search LAN menu
1830  */
1831 XBBool
CreateSearchLanMenu(void * par)1832 CreateSearchLanMenu (void *par)
1833 {
1834 	XBAtom *atom = par;
1835 	int i;
1836 
1837 	assert (NULL != atom);
1838 	networkAtom = *atom;
1839 	/* setup */
1840 	memset (networkGame, 0, sizeof (networkGame));
1841 	(void)RetrieveGameHost (CT_Local, networkAtom, &cfgServer);
1842 	/* build menu */
1843 	MenuClear ();
1844 	/* Title */
1845 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Search LAN for Games");
1846 	/* list of games */
1847 	MenuSetActive (MenuAddGameHeader (SEARCH_LEFT, SEARCH_TOP, SEARCH_WIDTH), XBFalse);
1848 	for (i = 0; i < NUM_SEARCH_ROWS; i++) {
1849 		networkItem[i] =
1850 			MenuAddGameEntry (SEARCH_LEFT, SEARCH_ROW (i), SEARCH_WIDTH,
1851 							  (const XBNetworkGame **)networkGame + i, ButtonStartLanGame);
1852 		MenuSetActive (networkItem[i], XBFalse);
1853 	}
1854 	/* Buttons */
1855 	MenuSetAbort (MenuAddHButton
1856 				  (5 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonExitSearchLan, par));
1857 	MenuSetDefault (MenuAddHButton
1858 					(17 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Refresh", ButtonRefreshSearchLan,
1859 					 par));
1860 	/* add polling routine */
1861 	MenuAddCyclic (PollNetworkGame, NULL);
1862 	/* query for local games */
1863 	Client_StartQuery ();
1864 
1865 	// MenuSetLinks (); should work infinite loop ??
1866 	/* that's all */
1867 	return XBFalse;
1868 }								/* CreateSearchLanMenu */
1869 
1870 /***********************
1871  * search central menu *
1872  ***********************/
1873 
1874 /*
1875  * central entry activated
1876  */
1877 static XBBool
ButtonStartCentralGame(void * par)1878 ButtonStartCentralGame (void *par)
1879 {
1880 	const XBNetworkGame **ptr = par;
1881 	XBBool connect;
1882 
1883 	assert (NULL != ptr);
1884 	if (NULL == *ptr) {
1885 		return XBFalse;
1886 	}
1887 
1888 	/* get server connection */
1889 	cfgServer.name = (*ptr)->host;
1890 	cfgServer.port = (*ptr)->port;
1891 	/* store in database */
1892 	StoreGameHost (CT_Local, networkAtom, &cfgServer);
1893 	/* now try connection */
1894 	connect = Client_Connect (&cfgServer);
1895 	/* clean up */
1896 	Client_StopQuery ();
1897 	memset (networkGame, 0, sizeof (networkGame));
1898 	if (!connect) {
1899 		/* connection failed */
1900 		GUI_ErrorMessage ("Connection to %s:%hu failed", serverName, serverPort);
1901 		return CreateSearchCentralMenu (&networkAtom);
1902 	}
1903 
1904 	return CreateClientWaitMenu (&networkAtom);
1905 }								/* ButtonStartCentralGame */
1906 
1907 /*
1908  * refresh button activated
1909  */
1910 XBBool
ButtonRefreshSearchCentral(void * par)1911 ButtonRefreshSearchCentral (void *par)
1912 {
1913 	unsigned i;
1914 
1915 	/* delete old games */
1916 	teamMode = 0;
1917 	memset (networkGame, 0, sizeof (networkGame));
1918 	for (i = 0; i < NUM_SEARCH_ROWS; i++) {
1919 		MenuSetActive (networkItem[i], XBFalse);
1920 	}
1921 	/* starts new query */
1922 	Client_RestartQuery ();
1923 	return XBFalse;
1924 }								/* ButtonRefreshSearchCentral */
1925 
1926 /*
1927  *  exit button activated
1928  */
1929 static XBBool
ButtonExitSearchCentral(void * par)1930 ButtonExitSearchCentral (void *par)
1931 {
1932 	/* stop network search */
1933 	Client_StopQuery ();
1934 	teamMode = 0;
1935 	/* back to client menu */
1936 	return CreateJoinNetGameMenu (par);
1937 }								/* ButtonExitSearchCentral */
1938 
1939 /*
1940  * search CENTRAL for network games XBCC
1941  */
1942 XBBool
CreateSearchCentralMenu(void * par)1943 CreateSearchCentralMenu (void *par)
1944 {
1945 	XBAtom *atom = par;
1946 	int i;
1947 
1948 	assert (NULL != atom);
1949 	networkAtom = *atom;
1950 	/* setup */
1951 	memset (networkGame, 0, sizeof (networkGame));
1952 	(void)RetrieveGameHost (CT_Local, networkAtom, &cfgServer);
1953 	/* build menu */
1954 	MenuClear ();
1955 	/* Title */
1956 	MenuAddLabel2 (TITLE_LEFT - 25, TITLE_TOP - 15, TITLE_WIDTH + 50,
1957 				   "Lamer Rado waits for you in http://xblast.sf.net/irc/");
1958 	MenuAddLabel (TITLE_LEFT, TITLE_TOP, TITLE_WIDTH, "Central Games");
1959 	/* list of games */
1960 	MenuSetActive (MenuAddGameHeader (SEARCH_LEFT, SEARCH_TOP, SEARCH_WIDTH), XBFalse);
1961 	for (i = 0; i < NUM_SEARCH_ROWS; i++) {
1962 		networkItem[i] =
1963 			MenuAddGameEntry (SEARCH_LEFT, SEARCH_ROW (i), SEARCH_WIDTH,
1964 							  (const XBNetworkGame **)networkGame + i, ButtonStartCentralGame);
1965 		MenuSetActive (networkItem[i], XBFalse);
1966 	}
1967 	/* Buttons */
1968 	MenuSetAbort (MenuAddHButton
1969 				  (5 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Back", ButtonExitSearchCentral, par));
1970 	MenuSetDefault (MenuAddHButton
1971 					(17 * CELL_W / 2, MENU_BOTTOM, 4 * CELL_W, "Refresh",
1972 					 ButtonRefreshSearchCentral, par));
1973 	/* add polling routine */
1974 	MenuAddCyclic (PollNetworkGame, NULL);
1975 	/* query for local games */
1976 	Client_StartCentralQuery ();
1977 
1978 	// MenuSetLinks (); should work infinite loop ??
1979 	/* that's all */
1980 	return XBFalse;
1981 }								/* CreateSearchCentralMenu */
1982 
1983 /*
1984  * end of file menu_network.c
1985  */
1986