1 /*
2  * file mi_host.c - Menu item for host selection in networked games
3  *
4  * $Id: mi_host.c,v 1.25 2006/02/09 21:21:24 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  * local macors
28  */
29 #define FF_HOST_NAME_FOCUS     (FF_Small | FF_Black | FF_Center | FF_Outlined)
30 #define FF_HOST_NAME_NO_FOCUS  (FF_Small | FF_White | FF_Center)
31 #define FF_HOST_STATE_FOCUS    (FF_Large | FF_Black | FF_Center | FF_Outlined)
32 #define FF_HOST_STATE_NO_FOCUS (FF_Large | FF_White | FF_Center)
33 
34 /*
35  * local types
36  */
37 typedef struct
38 {
39 	XBMenuItem item;			/* generic item data */
40 	/* host name */
41 	const char **pText;			/* link to current host name string */
42 	const char *cText;			/* displayed host name string */
43 	Sprite *tSprite;			/* host name text sprite */
44 	/* host state */
45 	XBHostState *pState;		/* link to current host state */
46 	XBHostState cState;			/* displayed host state */
47 	Sprite *sSprite;			/* host state text sprite */
48 	/* host ping */
49 	const int *pPing;			/* link to current ping time */
50 	int cPing;					/* currently displayed ping value */
51 	char tPing[16];				/* currently displayer ping string */
52 	Sprite *pSprite;			/* host ping text sprite */
53 
54 	/* host state requests */
55 	unsigned id;				/* host id */
56 	XBHSFocusFunc focusFunc;	/* handler for state focus changes */
57 	XBHSChangeFunc chgFunc;		/* handler for local state changes */
58 	XBHSUpdateFunc upFunc;		/* handler for ping/state updates */
59 	/* locally requested state */
60 	XBHostState lState;			/* current local requested state */
61 	Sprite *lSprite;			/* local request text sprite */
62 	/* requests known to server */
63 	XBHostState cStateReq[MAX_HOSTS];	/* displayed externak requests */
64 	char tRequests[MAX_HOSTS + 1];	/* displayed requests string */
65 	Sprite *rSprite;			/* requests text sprite */
66 } XBMenuHostItem;
67 
68 typedef struct
69 {
70 	XBMenuItem item;			/* generic item data */
71 	/* team state */
72 	XBTeamState *pTeam;			/* link to current team state */
73 	XBTeamState cTeam;			/* displayed team state */
74 	Sprite *sSprite;			/* team state text sprite */
75 	/* team state requests */
76 	unsigned id;				/* host id */
77 	unsigned player;			/* player id */
78 	XBTSFocusFunc focusFunc;	/* handler for team focus changes */
79 	XBTSChangeFunc chgFunc;		/* handler for local team changes */
80 	XBTSUpdateFunc upFunc;		/* handler for team updates */
81 	/* locally requested team */
82 	XBTeamState lTeam;			/* currently requested team */
83 	Sprite *lSprite;			/* state request text sprite */
84 	/* requests known to server */
85 	XBTeamState cTeamReq[MAX_HOSTS];	/* display team requests */
86 	char tRequests[MAX_HOSTS + 1];	/* displayed requests string */
87 	Sprite *rSprite;			/* requests text sprite */
88 } XBMenuTeamItem;
89 
90 /*
91  * local variables
92  */
93 static XBHostState serverState = XBHS_Server;
94 static const char *stateText[NUM_XBHS] = {
95 	"?",						/* XBHS_None */
96 	"...",						/* XBHS_Wait */
97 	"In",						/* XBHS_In */
98 	"Out",						/* XBHS_Out */
99 	"Srv",						/* XBHS_Server */
100 	"Go!",						/* XBHS_Ready */
101 };
102 
103 static const char *teamText[NUM_XBTS] = {
104 	"",							/* XBTS_Invalid */
105 	"None",						/* XBTS_None */
106 	"Red",						/* XBTS_Red */
107 	"Green",					/* XBTS_Green */
108 	"Blue",						/* XBTS_Blue */
109 	"Out",						/* XBTS_Out */
110 };
111 
112 /*******************
113  * shared routines *
114  *******************/
115 
116 /*
117  * shared host focus handler
118  */
119 static void
MenuHostFocusShared(XBMenuItem * ptr,XBBool flag)120 MenuHostFocusShared (XBMenuItem * ptr, XBBool flag)
121 {
122 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
123 
124 	assert (NULL != host);
125 	assert (NULL != host->tSprite);
126 	assert (NULL != host->sSprite);
127 	SetSpriteAnime (host->tSprite, flag ? FF_HOST_NAME_FOCUS : FF_HOST_NAME_NO_FOCUS);
128 	SetSpriteAnime (host->sSprite, flag ? FF_HOST_STATE_FOCUS : FF_HOST_STATE_NO_FOCUS);
129 	if (NULL != host->pSprite) {
130 		SetSpriteAnime (host->pSprite, flag ? FF_HOST_NAME_FOCUS : FF_HOST_NAME_NO_FOCUS);
131 	}
132 }								/* MenuHostFocusShared */
133 
134 /*
135  * polling a host item
136  */
137 static void
MenuHostPollShared(XBMenuItem * ptr)138 MenuHostPollShared (XBMenuItem * ptr)
139 {
140 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
141 	assert (NULL != host);
142 	assert (NULL != host->tSprite);
143 	assert (NULL != host->sSprite);
144 	/* check state change, old style: link to array in menu_network.c */
145 	if (*host->pState != host->cState) {
146 		host->cState = *host->pState;
147 		assert (host->cState < NUM_XBHS);
148 		SetSpriteText (host->sSprite, stateText[host->cState]);
149 	}
150 	/* check name change */
151 	if (*host->pText != host->cText) {
152 		host->cText = *host->pText;
153 		SetSpriteText (host->tSprite, host->cText);
154 	}
155 	/* update ping, old style: link to array in menu_network.c */
156 	if (NULL != host->pPing && *host->pPing != host->cPing) {
157 		host->cPing = *host->pPing;
158 		if (host->cPing < 0) {
159 			host->tPing[0] = 0;
160 		}
161 		else {
162 			sprintf (host->tPing, "%u ms", host->cPing);
163 		}
164 		SetSpriteText (host->pSprite, host->tPing);
165 	}
166 }								/* MenuSharedPoll */
167 
168 /*
169  * shared team focus handler
170  */
171 static void
MenuTeamFocusShared(XBMenuItem * ptr,XBBool flag)172 MenuTeamFocusShared (XBMenuItem * ptr, XBBool flag)
173 {
174 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
175 
176 	assert (NULL != team);
177 	assert (NULL != team->sSprite);
178 	SetSpriteAnime (team->sSprite, flag ? FF_HOST_NAME_FOCUS : FF_HOST_NAME_NO_FOCUS);
179 
180 }								/* MenuTeamFocusShared */
181 
182 /*
183  * polling a team item
184  */
185 static void
MenuTeamPollShared(XBMenuItem * ptr)186 MenuTeamPollShared (XBMenuItem * ptr)
187 {
188 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
189 
190 	assert (NULL != team);
191 	/* state */
192 	if (*team->pTeam != team->cTeam) {
193 		team->cTeam = *team->pTeam;
194 		assert (team->cTeam < NUM_XBTS);
195 		SetSpriteText (team->sSprite, teamText[team->cTeam]);
196 	}
197 }								/* MenuTeamPollShared */
198 
199 /*********************
200  * generic host item *
201  *********************/
202 
203 /*
204  * host item receives focus
205  */
206 static void
MenuHostFocus(XBMenuItem * ptr,XBBool flag)207 MenuHostFocus (XBMenuItem * ptr, XBBool flag)
208 {
209 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
210 	assert (NULL != host->focusFunc);
211 	(*host->focusFunc) (host->id);
212 	MenuHostFocusShared (ptr, flag);
213 }								/* MenuHostFocus */
214 
215 /*
216  * host item selected
217  */
218 static void
MenuHostSelect(XBMenuItem * ptr)219 MenuHostSelect (XBMenuItem * ptr)
220 {
221 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
222 	assert (NULL != host);
223 	assert (NULL != host->chgFunc);
224 	assert (host->id < MAX_HOSTS);
225 	if ((*host->chgFunc) (host->id, &host->lState)) {
226 		/* update the local request sprite */
227 		if (host->lState == host->cState || host->lState == XBHS_None) {
228 			SetSpriteText (host->lSprite, "");
229 		}
230 		else {
231 			SetSpriteText (host->lSprite, stateText[host->lState]);
232 		}
233 	}
234 }								/* MenuHostSelect */
235 
236 /*
237  * host item mouse event
238  */
239 static void
MenuHostMouse(XBMenuItem * ptr,XBEventCode code)240 MenuHostMouse (XBMenuItem * ptr, XBEventCode code)
241 {
242 	if (code == XBE_MOUSE_1) {
243 		MenuHostSelect (ptr);
244 	}
245 }								/* MenuHostMouse */
246 
247 /*
248  * host item polling
249  */
250 static void
MenuHostPoll(XBMenuItem * ptr)251 MenuHostPoll (XBMenuItem * ptr)
252 {
253 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
254 #ifdef REQUESTS
255 	unsigned i;
256 #endif
257 	assert (NULL != host);
258 	assert (NULL != host->tSprite);
259 	assert (NULL != host->sSprite);
260 	if ((*host->upFunc) (host->id, &host->cState, &host->cStateReq[0], &host->cPing)) {
261 		assert (host->cState < NUM_XBHS);
262 		/* create requests and ping */
263 		if (host->cState == XBHS_None) {
264 			host->tRequests[0] = (char)0;
265 			host->tPing[0] = (char)0;
266 		}
267 		else {
268 #ifdef REQUESTS
269 			/* update requests text */
270 			for (i = 0; i < MAX_HOSTS; i++) {
271 				host->tRequests[i] = *stateText[host->cStateReq[i]];
272 			}
273 			host->tRequests[MAX_HOSTS] = (char)0;
274 #endif
275 			/* update ping text */
276 			if (host->cPing < 0) {
277 				host->tPing[0] = (char)0;	/* ping undefined, display nothing */
278 			}
279 			else {
280 				sprintf (host->tPing, "%u ms", host->cPing);
281 			}
282 		}
283 		/* display requests, ping, current */
284 #ifdef REQUESTS
285 		SetSpriteText (host->rSprite, host->tRequests);
286 #endif
287 		SetSpriteText (host->sSprite, stateText[host->cState]);
288 		SetSpriteText (host->pSprite, host->tPing);
289 	}
290 	/* clear local request sprite if it coincides with current state or not set */
291 	if (host->lState == XBHS_None || host->lState == host->cState) {
292 		SetSpriteText (host->lSprite, "");
293 	}
294 	/* check name change, direct link */
295 	if (*(host->pText + host->id) != host->cText) {
296 		host->cText = *(host->pText + host->id);
297 		SetSpriteText (host->tSprite, host->cText);
298 	}
299 }								/* MenuHostPoll */
300 
301 /*
302  * create generic host button
303  */
304 XBMenuItem *
MenuCreateHost(int x,int y,int w,unsigned client,const char ** pText,XBHSFocusFunc focusFunc,XBHSChangeFunc chgFunc,XBHSUpdateFunc upFunc)305 MenuCreateHost (int x, int y, int w, unsigned client, const char **pText, XBHSFocusFunc focusFunc,
306 				XBHSChangeFunc chgFunc, XBHSUpdateFunc upFunc)
307 {
308 	/* create item */
309 	XBMenuHostItem *host = calloc (1, sizeof (*host));
310 	assert (host != NULL);
311 	MenuSetItem (&host->item, MIT_Host, x, y, w, CELL_H, MenuHostFocus, MenuHostSelect,
312 				 MenuHostMouse, MenuHostPoll);
313 	/* remember host id */
314 	host->id = client;
315 	/* set handlers */
316 	host->focusFunc = focusFunc;
317 	host->chgFunc = chgFunc;
318 	host->upFunc = upFunc;
319 	/* set initial state info */
320 	host->cState = XBHS_None;
321 	host->sSprite =
322 		CreateTextSprite (stateText[host->cState], (x + 1) * BASE_X, (y + 1) * BASE_Y,
323 						  (w / 4) * BASE_X, CELL_H / 2 * BASE_Y, FF_HOST_NAME_NO_FOCUS, SPM_MAPPED);
324 	/* set initial local request info */
325 	host->lState = XBHS_None;
326 	host->lSprite =
327 		CreateTextSprite ("", (x + w / 5) * BASE_X, (y + 1) * BASE_Y, (w / 4) * BASE_X,
328 						  CELL_H / 2 * BASE_Y, FF_HOST_NAME_NO_FOCUS, SPM_MAPPED);
329 	/* set initial requests info */
330 	memset (host->cStateReq, 0, sizeof (host->cStateReq));
331 	host->rSprite =
332 		CreateTextSprite (host->tRequests, (x + 1) * BASE_X, (y + CELL_H / 2) * BASE_Y,
333 						  (w / 2) * BASE_X, (CELL_H / 2 - 1) * BASE_Y, FF_HOST_NAME_NO_FOCUS,
334 						  SPM_MAPPED);
335 	/* set initial ping info */
336 	host->cPing = -1;
337 	host->tPing[0] = (char)0;
338 	host->pSprite =
339 		CreateTextSprite (host->tPing, (x + w / 2) * BASE_X, (y + CELL_H / 2) * BASE_Y,
340 						  (w / 2 - 1) * BASE_X, (CELL_H / 2 - 1) * BASE_Y, FF_HOST_NAME_NO_FOCUS,
341 						  SPM_MAPPED);
342 	/* link host name */
343 	assert (pText != NULL);
344 	host->pText = pText;
345 	host->cText = *(pText + host->id);
346 	host->tSprite =
347 		CreateTextSprite (host->cText, (x + 2 * w / 5) * BASE_X, (y + 1) * BASE_Y,
348 						  (3 * w / 5 - 1) * BASE_X, CELL_H / 2 * BASE_Y, FF_HOST_NAME_NO_FOCUS,
349 						  SPM_MAPPED);
350 	/* graphics */
351 	MenuAddLargeFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
352 	/* poll once */
353 	MenuHostPoll (&host->item);
354 	return &host->item;
355 }								/* MenuCreateServer */
356 
357 /********************
358  * server host item *
359  ********************/
360 
361 /*
362  * host item has focus
363  */
364 static void
MenuServerFocus(XBMenuItem * ptr,XBBool flag)365 MenuServerFocus (XBMenuItem * ptr, XBBool flag)
366 {
367 	MenuHostFocusShared (ptr, flag);
368 }								/* MenuServerFocus */
369 
370 /*
371  * host item selected
372  */
373 static void
MenuServerSelect(XBMenuItem * ptr)374 MenuServerSelect (XBMenuItem * ptr)
375 {
376 }								/* MenuServerSelect */
377 
378 /*
379  * host item mouse event
380  */
381 static void
MenuServerMouse(XBMenuItem * ptr,XBEventCode code)382 MenuServerMouse (XBMenuItem * ptr, XBEventCode code)
383 {
384 }								/* MenuServerMouse */
385 
386 /*
387  * polling
388  */
389 static void
MenuServerPoll(XBMenuItem * ptr)390 MenuServerPoll (XBMenuItem * ptr)
391 {
392 	MenuHostPollShared (ptr);
393 }								/* MenuServerPoll */
394 
395 /*
396  * create server button
397  */
398 XBMenuItem *
MenuCreateServer(int x,int y,int w,const char ** pText)399 MenuCreateServer (int x, int y, int w, const char **pText)
400 {
401 	/* create item */
402 	XBMenuHostItem *host = calloc (1, sizeof (*host));
403 	assert (host != NULL);
404 	MenuSetItem (&host->item, MIT_Host, x, y, w, CELL_H, MenuServerFocus, MenuServerSelect,
405 				 MenuServerMouse, MenuServerPoll);
406 	/* set server specific data */
407 	assert (pText != NULL);
408 	host->pText = pText;
409 	host->cText = *pText;
410 	host->pState = &serverState;
411 	host->cState = XBHS_None;
412 	/* sprite with host name */
413 	host->tSprite =
414 		CreateTextSprite (*pText, (x + 11) * BASE_X, y * BASE_Y, (w - 12) * BASE_X, CELL_H * BASE_Y,
415 						  FF_HOST_NAME_NO_FOCUS, SPM_MAPPED);
416 	/* sprite with host state */
417 	host->sSprite =
418 		CreateTextSprite (stateText[0], (x + 1) * BASE_X, y * BASE_Y, 9 * BASE_X, CELL_H * BASE_Y,
419 						  FF_HOST_STATE_NO_FOCUS, SPM_MAPPED);
420 	/* sprite with state request */
421 	host->lSprite = NULL;
422 	/* sprite with requests */
423 	host->rSprite = NULL;
424 	/* graphics */
425 	MenuAddLargeFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
426 	return &host->item;
427 }								/* MenuCreateServer */
428 
429 /********************
430  * client host item *
431  ********************/
432 
433 /*
434  * host item has focus
435  */
436 static void
MenuClientFocus(XBMenuItem * ptr,XBBool flag)437 MenuClientFocus (XBMenuItem * ptr, XBBool flag)
438 {
439 	MenuHostFocusShared (ptr, flag);
440 }								/* MenuClientFocus */
441 
442 /*
443  * host item selected
444  */
445 static void
MenuClientSelect(XBMenuItem * ptr)446 MenuClientSelect (XBMenuItem * ptr)
447 {
448 	XBMenuHostItem *host = (XBMenuHostItem *) ptr;
449 
450 	assert (NULL != host);
451 	assert (NULL != host->pState);
452 	switch (*host->pState) {
453 	case XBHS_In:
454 		*host->pState = XBHS_Out;
455 		break;
456 	case XBHS_Out:
457 		*host->pState = XBHS_In;
458 		break;
459 	default:
460 		break;
461 	}
462 }								/* MenuClientSelect */
463 
464 /*
465  * host item mouse event
466  */
467 static void
MenuClientMouse(XBMenuItem * ptr,XBEventCode code)468 MenuClientMouse (XBMenuItem * ptr, XBEventCode code)
469 {
470 	if (code == XBE_MOUSE_1) {
471 		MenuClientSelect (ptr);
472 	}
473 }								/* MenuClientMouse */
474 
475 /*
476  * polling
477  */
478 static void
MenuClientPoll(XBMenuItem * ptr)479 MenuClientPoll (XBMenuItem * ptr)
480 {
481 	MenuHostPollShared (ptr);
482 }								/* MenuClientPoll */
483 
484 /*
485  * create server button
486  */
487 XBMenuItem *
MenuCreateClient(int x,int y,int w,const char ** pText,XBHostState * pState,const int * pPing)488 MenuCreateClient (int x, int y, int w, const char **pText, XBHostState * pState, const int *pPing)
489 {
490 	/* create item */
491 	XBMenuHostItem *host = calloc (1, sizeof (*host));
492 	assert (host != NULL);
493 	MenuSetItem (&host->item, MIT_Host, x, y, w, CELL_H, MenuClientFocus, MenuClientSelect,
494 				 MenuClientMouse, MenuClientPoll);
495 	/* set server specific data */
496 	assert (pText != NULL);
497 	assert (pState != NULL);
498 	host->pText = pText;
499 	host->cText = *pText;
500 	host->pState = pState;
501 	host->cState = *pState;
502 	host->pPing = pPing;
503 	host->cPing = -1;
504 	host->rSprite = NULL;
505 	/* sprite with host name */
506 	host->tSprite =
507 		CreateTextSprite (*pText, (x + 11) * BASE_X, (y + 1) * BASE_Y, (w - 12) * BASE_X,
508 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_NO_FOCUS, SPM_MAPPED);
509 	/* sprite with ping to host */
510 	host->pSprite =
511 		CreateTextSprite (host->tPing, (x + 11) * BASE_X, (y + CELL_H / 2) * BASE_Y,
512 						  (w - 12) * BASE_X, (CELL_H / 2 - 1) * BASE_Y, FF_HOST_NAME_NO_FOCUS,
513 						  SPM_MAPPED);
514 	/* sprite with host state */
515 	host->sSprite =
516 		CreateTextSprite (stateText[*pState], (x + 1) * BASE_X, y * BASE_Y, 9 * BASE_X,
517 						  CELL_H * BASE_Y, FF_HOST_STATE_NO_FOCUS, SPM_MAPPED);
518 	/* sprite with state request */
519 	host->lSprite = NULL;
520 	/* sprite with requests */
521 	host->rSprite = NULL;
522 	/* graphics */
523 	MenuAddLargeFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
524 	return &host->item;
525 }								/* MenuCreateServer */
526 
527 /******************
528  * peer host item *
529  ******************/
530 
531 /*
532  * host item has focus
533  */
534 static void
MenuPeerFocus(XBMenuItem * ptr,XBBool flag)535 MenuPeerFocus (XBMenuItem * ptr, XBBool flag)
536 {
537 	MenuHostFocusShared (ptr, flag);
538 }								/* MenuPeerFocus */
539 
540 /*
541  * host item is selected
542  */
543 static void
MenuPeerSelect(XBMenuItem * ptr)544 MenuPeerSelect (XBMenuItem * ptr)
545 {
546 }								/* MenuPeerSelect */
547 
548 /*
549  * host item under mouse
550  */
551 static void
MenuPeerMouse(XBMenuItem * ptr,XBEventCode code)552 MenuPeerMouse (XBMenuItem * ptr, XBEventCode code)
553 {
554 }								/* MenuPeerMouse */
555 
556 /*
557  * polling
558  */
559 static void
MenuPeerPoll(XBMenuItem * ptr)560 MenuPeerPoll (XBMenuItem * ptr)
561 {
562 	MenuHostPollShared (ptr);
563 }								/* MenuPeerPoll */
564 
565 /*
566  * create peer item
567  */
568 XBMenuItem *
MenuCreatePeer(int x,int y,int w,const char ** pText,XBHostState * pState,const int * pPing)569 MenuCreatePeer (int x, int y, int w, const char **pText, XBHostState * pState, const int *pPing)
570 {
571 	/* create item */
572 	XBMenuHostItem *host = calloc (1, sizeof (*host));
573 	assert (host != NULL);
574 	MenuSetItem (&host->item, MIT_Host, x, y, w, CELL_H, MenuPeerFocus, MenuPeerSelect,
575 				 MenuPeerMouse, MenuPeerPoll);
576 	/* set server specific data */
577 	assert (pText != NULL);
578 	assert (pState != NULL);
579 	host->pText = pText;
580 	host->cText = *pText;
581 	host->pState = pState;
582 	host->cState = *pState;
583 	host->pPing = pPing;
584 	host->cPing = -1;
585 	host->rSprite = NULL;
586 	/* sprite with host name */
587 	host->tSprite =
588 		CreateTextSprite (*pText, (x + 11) * BASE_X, (y + 1) * BASE_Y, (w - 12) * BASE_X,
589 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_NO_FOCUS, SPM_MAPPED);
590 	/* sprite with ping to host */
591 	host->pSprite =
592 		CreateTextSprite (host->tPing, (x + 11) * BASE_X, (y + CELL_H / 2) * BASE_Y,
593 						  (w - 12) * BASE_X, (CELL_H / 2 - 1) * BASE_Y, FF_HOST_NAME_NO_FOCUS,
594 						  SPM_MAPPED);
595 	/* sprite with host state */
596 	host->sSprite =
597 		CreateTextSprite (stateText[*pState], (x + 1) * BASE_X, y * BASE_Y, 9 * BASE_X,
598 						  CELL_H * BASE_Y, FF_HOST_STATE_NO_FOCUS, SPM_MAPPED);
599 	/* sprite with state request */
600 	host->lSprite = NULL;
601 	/* sprite with requests */
602 	host->rSprite = NULL;
603 	/* graphics */
604 	MenuAddLargeFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
605 	return &host->item;
606 }								/* MenuCreateServer */
607 
608 /*********************
609  * generic team item *
610  *********************/
611 
612 /*
613  * team receives focus
614  */
615 static void
MenuTeamFocus(XBMenuItem * ptr,XBBool flag)616 MenuTeamFocus (XBMenuItem * ptr, XBBool flag)
617 {
618 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
619 	assert (NULL != team->focusFunc);
620 	(*team->focusFunc) (team->id, team->player);
621 	MenuTeamFocusShared (ptr, flag);
622 }								/* MenuTeamFocus */
623 
624 /*
625  * team item is selected
626  */
627 static void
MenuTeamSelect(XBMenuItem * ptr)628 MenuTeamSelect (XBMenuItem * ptr)
629 {
630 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
631 
632 	assert (NULL != team);
633 	/* first local request, init to current, if necessary */
634 	if (team->lTeam == XBTS_Invalid) {
635 		team->lTeam = team->cTeam;
636 	}
637 	/* get next reasonable local request */
638 	if ((*team->chgFunc) (team->id, team->player, &team->lTeam)) {
639 		assert (team->lTeam < NUM_XBTS);
640 		/* no display if equal to current or invalid */
641 #ifdef REQUESTS
642 		if (team->cTeam == team->lTeam || team->lTeam == XBTS_Invalid) {
643 			SetSpriteText (team->lSprite, "");
644 		}
645 		else {
646 			SetSpriteText (team->lSprite, teamText[team->lTeam]);
647 		}
648 #endif
649 	}
650 }								/* MenuTeamSelect */
651 
652 /*
653  * team item mouse event
654  */
655 static void
MenuTeamMouse(XBMenuItem * ptr,XBEventCode code)656 MenuTeamMouse (XBMenuItem * ptr, XBEventCode code)
657 {
658 	if (code == XBE_MOUSE_1) {
659 		MenuTeamSelect (ptr);
660 	}
661 }								/* MenuTeamMouse */
662 
663 /*
664  * polling a team item
665  */
666 static void
MenuTeamPoll(XBMenuItem * ptr)667 MenuTeamPoll (XBMenuItem * ptr)
668 {
669 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
670 #ifdef REQUESTS
671 	unsigned i;
672 #endif
673 	assert (NULL != team);
674 	assert (NULL != team->upFunc);
675 	/* update team data */
676 	if ((*team->upFunc) (team->id, team->player, &team->cTeam, team->cTeamReq)) {
677 		assert (team->cTeam < NUM_XBTS);
678 		/* reset local request if state invalid */
679 		if (team->cTeam == XBTS_Invalid) {
680 			team->lTeam = XBTS_Invalid;
681 		}
682 		/* update state */
683 		SetSpriteText (team->sSprite, teamText[team->cTeam]);
684 		/* check if local request needs to be cleared */
685 		if (team->cTeam == team->lTeam) {
686 			SetSpriteText (team->lSprite, "");
687 		}
688 		/* update requests */
689 #ifdef REQUESTS
690 		for (i = 0; i < MAX_HOSTS; i++) {
691 			team->tRequests[i] = *teamText[team->cTeamReq[i]];
692 		}
693 		team->tRequests[MAX_HOSTS] = (char)0;
694 		SetSpriteText (team->rSprite, team->tRequests);
695 #endif
696 	}
697 }								/* MenuTeamPoll */
698 
699 /*
700  * create team item
701  */
702 XBMenuItem *
MenuCreateTeam(int x,int y,int w,unsigned id,unsigned player,XBTSFocusFunc focusFunc,XBTSChangeFunc chgFunc,XBTSUpdateFunc upFunc)703 MenuCreateTeam (int x, int y, int w, unsigned id, unsigned player, XBTSFocusFunc focusFunc,
704 				XBTSChangeFunc chgFunc, XBTSUpdateFunc upFunc)
705 {
706 	/* create item */
707 	XBMenuTeamItem *team = calloc (1, sizeof (*team));
708 	assert (team != NULL);
709 	MenuSetItem (&team->item, MIT_Team, x, y, w, CELL_H, MenuTeamFocus, MenuTeamSelect,
710 				 MenuTeamMouse, MenuTeamPoll);
711 	/* store id, player */
712 	team->id = id;
713 	team->player = player;
714 	/* set handler */
715 	team->focusFunc = focusFunc;
716 	team->chgFunc = chgFunc;
717 	team->upFunc = upFunc;
718 	/* team state */
719 	team->cTeam = XBTS_Invalid;
720 	team->sSprite =
721 		CreateTextSprite (teamText[team->cTeam], (x + 1) * BASE_X, y * BASE_Y, w / 4 * BASE_X,
722 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_FOCUS, SPM_MAPPED);
723 	/* team state request */
724 	team->lTeam = XBTS_Invalid;
725 	team->lSprite =
726 		CreateTextSprite (teamText[team->lTeam], (x + w / 4) * BASE_X, y * BASE_Y, w / 4 * BASE_X,
727 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_FOCUS, SPM_MAPPED);
728 	/* team requests */
729 	memset (team->cTeamReq, 0, sizeof (team->cTeamReq));
730 	team->tRequests[0] = (char)0;
731 	team->rSprite =
732 		CreateTextSprite (team->tRequests, (x + w / 2) * BASE_X, y * BASE_Y, (w / 2 - 1) * BASE_X,
733 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_FOCUS, SPM_MAPPED);
734 	/* graphics */
735 	MenuAddSmallFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
736 	/* poll once */
737 	MenuTeamPoll (&team->item);
738 	return &team->item;
739 }								/* MenuCreateTeam */
740 
741 /************************
742  * team item for a peer *
743  ************************/
744 
745 /*
746  * team receives focus
747  */
748 static void
MenuPeerTeamFocus(XBMenuItem * ptr,XBBool flag)749 MenuPeerTeamFocus (XBMenuItem * ptr, XBBool flag)
750 {
751 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
752 
753 	assert (NULL != team);
754 	assert (NULL != team->sSprite);
755 	SetSpriteAnime (team->sSprite, flag ? FF_HOST_NAME_FOCUS : FF_HOST_NAME_NO_FOCUS);
756 
757 }								/* MenuPeerTeamFocus */
758 
759 /*
760  * peer team item selcted
761  */
762 static void
MenuPeerTeamSelect(XBMenuItem * ptr)763 MenuPeerTeamSelect (XBMenuItem * ptr)
764 {
765 }								/* MenuPeerTeamSelect */
766 
767 /*
768  * peer team item mouse event
769  */
770 static void
MenuPeerTeamMouse(XBMenuItem * ptr,XBEventCode code)771 MenuPeerTeamMouse (XBMenuItem * ptr, XBEventCode code)
772 {
773 }								/* MenuPeerTeamMouse */
774 
775 /*
776  * polling a team item
777  */
778 static void
MenuPeerTeamPoll(XBMenuItem * ptr)779 MenuPeerTeamPoll (XBMenuItem * ptr)
780 {
781 	MenuTeamPollShared (ptr);
782 }								/* MenuPeerTeamPoll */
783 
784 /*
785  * create team item for a peer
786  */
787 XBMenuItem *
MenuCreatePeerTeam(int x,int y,int w,XBTeamState * pTeam)788 MenuCreatePeerTeam (int x, int y, int w, XBTeamState * pTeam)
789 {
790 	/* create item */
791 	XBMenuTeamItem *team = calloc (1, sizeof (*team));
792 	assert (team != NULL);
793 	MenuSetItem (&team->item, MIT_Team, x, y, w, CELL_H, MenuPeerTeamFocus, MenuPeerTeamSelect,
794 				 MenuPeerTeamMouse, MenuPeerTeamPoll);
795 	/* set server specific data */
796 	assert (pTeam != NULL);
797 	team->pTeam = pTeam;
798 	team->cTeam = *pTeam;
799 	/* sprite with team state */
800 	team->sSprite =
801 		CreateTextSprite (teamText[*pTeam], (x + 1) * BASE_X, y * BASE_Y, (w - 2) * BASE_X,
802 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_FOCUS, SPM_MAPPED);
803 	/* sprite with team requests */
804 	team->lSprite = NULL;
805 	/* sprite with team requests */
806 	team->rSprite = NULL;
807 	/* graphics */
808 	MenuAddSmallFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
809 	return &team->item;
810 }								/* MenuCreateTeam */
811 
812 /************************
813  * team item for server *
814  ************************/
815 
816 /*
817  * team receives focus
818  */
819 static void
MenuServerTeamFocus(XBMenuItem * ptr,XBBool flag)820 MenuServerTeamFocus (XBMenuItem * ptr, XBBool flag)
821 {
822 	MenuTeamFocusShared (ptr, flag);
823 
824 }								/* MenuServerTeamFocus */
825 
826 /*
827  * team item is selected
828  */
829 static void
MenuServerTeamSelect(XBMenuItem * ptr)830 MenuServerTeamSelect (XBMenuItem * ptr)
831 {
832 	XBMenuTeamItem *team = (XBMenuTeamItem *) ptr;
833 
834 	assert (NULL != team);
835 	assert (NULL != team->pTeam);
836 	if (*team->pTeam < NUM_XBTS - 1) {
837 		*team->pTeam = *team->pTeam + 1;
838 	}
839 	else {
840 		*team->pTeam = 2;
841 	}
842 }								/* MenuTeamSelect */
843 
844 /*
845  * team item mouse event
846  */
847 static void
MenuServerTeamMouse(XBMenuItem * ptr,XBEventCode code)848 MenuServerTeamMouse (XBMenuItem * ptr, XBEventCode code)
849 {
850 	if (code == XBE_MOUSE_1) {
851 		MenuServerTeamSelect (ptr);
852 	}
853 }								/* MenuTeamMouse */
854 
855 /*
856  * polling a team item
857  */
858 static void
MenuServerTeamPoll(XBMenuItem * ptr)859 MenuServerTeamPoll (XBMenuItem * ptr)
860 {
861 	MenuTeamPollShared (ptr);
862 }								/* MenuServerTeamPoll */
863 
864 /*
865  * create team item for server
866  */
867 XBMenuItem *
MenuCreateServerTeam(int x,int y,int w,XBTeamState * pTeam)868 MenuCreateServerTeam (int x, int y, int w, XBTeamState * pTeam)
869 {
870 	/* create item */
871 	XBMenuTeamItem *team = calloc (1, sizeof (*team));
872 	assert (team != NULL);
873 	MenuSetItem (&team->item, MIT_Team, x, y, w, CELL_H, MenuServerTeamFocus, MenuServerTeamSelect,
874 				 MenuServerTeamMouse, MenuServerTeamPoll);
875 	/* set server specific data */
876 	assert (pTeam != NULL);
877 	team->pTeam = pTeam;
878 	team->cTeam = *pTeam;
879 	/* sprite with team state */
880 	team->sSprite =
881 		CreateTextSprite (teamText[*pTeam], (x + 1) * BASE_X, y * BASE_Y, (w - 2) * BASE_X,
882 						  (CELL_H / 2) * BASE_Y, FF_HOST_NAME_FOCUS, SPM_MAPPED);
883 	/* sprite with current team request */
884 	team->lSprite = NULL;
885 	/* sprite with team requests */
886 	team->rSprite = NULL;
887 	/* graphics */
888 	MenuAddSmallFrame (x / CELL_W, (x + w - 1) / CELL_W, y / CELL_H);
889 	return &team->item;
890 }								/* MenuCreateTeam */
891 
892 /***************
893  * destructors *
894  ***************/
895 
896 /*
897  * delete a host item
898  */
899 void
MenuDeleteHost(XBMenuItem * item)900 MenuDeleteHost (XBMenuItem * item)
901 {
902 	XBMenuHostItem *host = (XBMenuHostItem *) item;
903 
904 	assert (NULL != host);
905 	assert (NULL != host->tSprite);
906 	assert (NULL != host->sSprite);
907 	DeleteSprite (host->tSprite);
908 	DeleteSprite (host->sSprite);
909 	if (NULL != host->pSprite) {
910 		DeleteSprite (host->pSprite);
911 	}
912 	if (NULL != host->rSprite) {
913 		DeleteSprite (host->rSprite);
914 	}
915 	if (NULL != host->lSprite) {
916 		DeleteSprite (host->lSprite);
917 	}
918 }								/* MenuDeleteHost */
919 
920 /*
921  * delete a team item
922  */
923 void
MenuDeleteTeam(XBMenuItem * item)924 MenuDeleteTeam (XBMenuItem * item)
925 {
926 	XBMenuTeamItem *team = (XBMenuTeamItem *) item;
927 
928 	assert (NULL != team);
929 	assert (NULL != team->sSprite);
930 	DeleteSprite (team->sSprite);
931 	if (NULL != team->rSprite) {
932 		DeleteSprite (team->rSprite);
933 	}
934 	if (NULL != team->lSprite) {
935 		DeleteSprite (team->lSprite);
936 	}
937 }								/* MenuDeleteTeam */
938 
939 /*
940  * end of file mi_host.c
941  */
942