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