d1x->d2x
[btb/d2x.git] / main / netlist.c
1 /*
2  * $Source: /cvs/cvsroot/d2x/main/netlist.c,v $
3  * $Revision: 1.2 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-14 09:24:19 $
6  *
7  * Descent II-a-like network game join menu
8  * Arne de Bruijn, 1998
9  *
10  * $Log: not supported by cvs2svn $
11  * Revision 1.1  2002/02/14 09:05:33  bradleyb
12  * Lotsa networking stuff from d1x
13  *
14  *
15  */
16
17 #ifdef HAVE_CONFIG_H
18 #include <conf.h>
19 #endif
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "pstypes.h"
26 #include "timer.h"
27 #include "gr.h"
28 #include "palette.h"
29 #include "inferno.h"
30 #include "mono.h"
31 #include "key.h"
32 #include "error.h"
33 #include "netmisc.h"
34 #include "network.h"
35 #include "ipx.h"
36 #include "game.h"
37 #include "multi.h"
38 #include "text.h"
39 //added 4/18/99 Matt Mueller - show radar in game info
40 #include "multipow.h"
41 //end addition -MM
42
43 #include "gamefont.h"
44 #include "u_mem.h"
45
46 #include "string.h"
47
48 //added on 1/5/99 by Victor Rachels for missiondir
49 #include "cfile.h"
50 //end this section addition
51
52 #define LINE_ITEMS 8
53 #define MAX_TEXT_LEN 25
54 // from network.c
55 extern int Network_games_changed;
56 extern netgame_info Active_games[MAX_ACTIVE_NETGAMES];
57 extern AllNetPlayers_info ActiveNetPlayers[MAX_ACTIVE_NETGAMES];
58 extern int num_active_games;
59 extern int Network_socket;
60 void network_listen();
61 void network_send_game_list_request();
62 // bitblt.c
63 void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest);
64
65 typedef struct bkg {
66   grs_canvas * menu_canvas;
67   grs_bitmap * saved;                   // The background under the menu.
68   grs_bitmap * background;
69   int background_is_sub;
70 } bkg;
71
72 extern grs_bitmap nm_background;
73
74 struct line_item {
75         int x, y;
76         int width;
77         char *value;
78 };
79
80 void network_draw_game(const netgame_info *game) {
81 }
82
83 char *network_mode_text(const netgame_info *game) {
84         //edit 4/18/99 Matt Mueller - GTEAM?  heh.  Should be "TEAM" I think.
85         static char *names[4]={"ANRCHY", "TEAM", "ROBO", "COOP"};
86         //end edit -MM
87 #ifndef SHAREWARE
88         if (game->gamemode >= 4 ||
89             (game->protocol_version != MULTI_PROTO_VERSION &&
90              (game->protocol_version != MULTI_PROTO_D2X_VER ||
91               game->required_subprotocol > MULTI_PROTO_D2X_MINOR)))
92             return "UNSUP";
93 #endif
94         return names[game->gamemode];
95 }
96
97 char *network_status_text(const netgame_info *game, int activeplayers) {
98         switch (game->game_status) {
99                 case NETSTAT_STARTING:
100                         return "Forming";
101                 case NETSTAT_PLAYING:
102                         if (game->game_flags & NETGAME_FLAG_CLOSED)
103                                 return "Closed";
104                         else if (activeplayers == game->max_numplayers)
105                                 return "Full";
106                         else
107                                 return "Open";
108                 default:
109                         return "Between";
110         }
111 }
112
113 static void network_update_item(const netgame_info *game, const AllNetPlayers_info *players, struct line_item li[]) {
114         int i, activeplayers = 0;
115         // get number of active players
116         for (i = 0; i < game->numplayers; i++)
117                 if (players->players[i].connected)
118                         activeplayers++;
119         strcpy(li[1].value, game->protocol_version == MULTI_PROTO_D2X_VER ? "+" : "");
120         strcpy(li[2].value, game->game_name);
121         strcpy(li[3].value, network_mode_text(game));
122
123         sprintf(li[4].value, "%d/%d", activeplayers, game->max_numplayers);
124 #ifndef SHAREWARE
125         strcpy(li[5].value, game->mission_title);
126 #else
127         strcpy(li[5].value, "Descent: First Strike");
128 #endif
129         if (game->levelnum < 0)
130                 sprintf(li[6].value, "S%d", -game->levelnum);
131         else    
132                 sprintf(li[6].value, "%d", game->levelnum);
133         strcpy(li[7].value, network_status_text(game, activeplayers));
134 }
135
136 static void update_items(struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS]) {
137         int i, j;
138
139         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
140                 if (i >= num_active_games) {
141                         for (j = 1; j < LINE_ITEMS; j++)
142                                 lis[i][j].value[0] = 0;
143                 } else
144                         network_update_item(&Active_games[i], &ActiveNetPlayers[i], lis[i]);
145         }
146 }
147
148 int network_menu_hskip=4;
149 int network_menu_width[LINE_ITEMS] = { 10, 6, 72, 37, 38, 66, 25, 40 };
150 int ref_network_menu_width[LINE_ITEMS] = { 10, 6, 72, 37, 38, 66, 25, 40 };
151 char *network_menu_title[LINE_ITEMS] = { "", "", "Game", "Mode", "#Plrs", "Mission", "Lev", "Status" };
152
153 static int selected_game;
154
155 static void draw_back(bkg *b, int x, int y, int w, int h) {
156        gr_bm_bitblt(b->background->bm_w-15, h, 5, y, 5, y, b->background, &(grd_curcanv->cv_bitmap) );
157 }
158
159 static void draw_item(bkg *b, struct line_item *li, int is_current) {
160         int i, w, h, aw, max_w, pad_w, y;
161         char str[MAX_TEXT_LEN], *p;
162
163         y = li[0].y;
164         if (is_current)
165                 gr_set_fontcolor(BM_XRGB(31, 27, 6), -1);
166         else
167                 gr_set_fontcolor(BM_XRGB(17, 17, 26), -1);
168         gr_get_string_size(" ...", &pad_w, &h, &aw);
169         draw_back(b, li[0].x, y, 
170          li[LINE_ITEMS-1].x + li[LINE_ITEMS-1].width - li[0].x, h);
171         for (i = 0; i < LINE_ITEMS; i++) {
172                 strcpy(str, li[i].value);
173                 gr_get_string_size(str, &w, &h, &aw);
174                 if (w > li[i].width) {
175                         max_w = li[i].width - pad_w;
176                         p = str + strlen(str);
177                         while (p > str && w > max_w) {
178                                 *(--p) = 0;
179                                 gr_get_string_size(str, &w, &h, &aw);
180                         }
181                         strcpy(p, " ...");
182                 }
183                 gr_ustring(li[i].x, y, str);
184         }
185 }
186
187 static void draw_list(bkg *bg,
188  struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS]) {
189         int i;
190         update_items(lis);
191         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
192                 draw_item(bg, lis[i], i == selected_game);
193         }
194 }
195 static void init_background(bkg *bg, int x, int y, int w, int h) {
196         bg->menu_canvas = gr_create_sub_canvas( &grd_curscreen->sc_canvas, x, y, w, h );
197         gr_set_current_canvas( bg->menu_canvas );
198
199         // Save the background under the menu...
200         bg->saved = gr_create_bitmap( w, h );
201         Assert( bg->saved != NULL );
202         gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg->saved );
203         gr_set_current_canvas( NULL );
204         nm_draw_background(x,y,x+w-1,y+h-1);
205         if (w > nm_background.bm_w || h > nm_background.bm_h){
206                 bg->background=gr_create_bitmap(w,h);
207                 gr_bitmap_scale_to(&nm_background,bg->background);
208                 bg->background_is_sub=0;
209         }else{
210                 bg->background = gr_create_sub_bitmap(&nm_background,0,0,w,h);
211                 bg->background_is_sub=1;
212         }
213         gr_set_current_canvas( bg->menu_canvas );
214 }
215
216 static void done_background(bkg *bg) {
217         gr_set_current_canvas(bg->menu_canvas);
218         gr_bitmap(0, 0, bg->saved);     
219         gr_free_bitmap(bg->saved);
220         if (bg->background_is_sub)
221                 gr_free_sub_bitmap( bg->background );
222         else
223                 gr_free_bitmap( bg->background );
224         gr_free_sub_canvas( bg->menu_canvas );
225 }
226
227
228 //added on 9/16-18/98 by Victor Rachels to add info boxes to netgameslist
229 void show_game_players(netgame_info game, AllNetPlayers_info players)
230 {
231  char pilots[(CALLSIGN_LEN+2)*MAX_PLAYERS];
232  int i;
233
234   memset(pilots,0,sizeof(char)*(CALLSIGN_LEN+2)*MAX_PLAYERS);
235
236    for(i=0;i<game.numplayers;i++)
237     if(players.players[i].connected)
238      {
239       strcat(pilots,players.players[i].callsign);
240       strcat(pilots,"\n");
241      }
242
243   nm_messagebox("Players", 1, TXT_OK, pilots);
244 }
245
246 void show_game_score(netgame_info game, AllNetPlayers_info players);
247
248 int show_game_stats(netgame_info game, AllNetPlayers_info players, int awesomeflag)
249 {
250  //edited 4/18/99 Matt Mueller - show radar flag and banned stuff too
251  //switched to the info/rinfo mode to 1)allow sprintf easily 2) save some
252  //cpu cycles not seeking to the end of the string each time.
253  char rinfo[512],*info=rinfo;
254
255   memset(info,0,sizeof(char)*256);
256
257 #ifndef SHAREWARE
258    if(!game.mission_name)
259 #endif
260     info+=sprintf(info,"Level: Descent: First Strike");
261 #ifndef SHAREWARE
262    else
263     info+=sprintf(info,game.mission_name);
264 #endif
265
266    switch(game.gamemode)
267     {
268      case 0 : info+=sprintf(info,"\nMode:  Anarchy"); break;
269      case 1 : info+=sprintf(info,"\nMode:  Team"); break;
270      case 2 : info+=sprintf(info,"\nMode:  Robo"); break;
271      case 3 : info+=sprintf(info,"\nMode:  Coop"); break;
272      default: info+=sprintf(info,"\nMode:  Unknown"); break;
273     }
274
275    switch(game.difficulty)
276     {
277      case 0 : info+=sprintf(info,"\nDiff:  Trainee"); break;
278      case 1 : info+=sprintf(info,"\nDiff:  Rookie"); break;
279      case 2 : info+=sprintf(info,"\nDiff:  Hotshot"); break;
280      case 3 : info+=sprintf(info,"\nDiff:  Ace"); break;
281      case 4 : info+=sprintf(info,"\nDiff:  Insane"); break;
282      default: info+=sprintf(info,"\nDiff:  Unknown"); break;
283     }
284
285    switch(game.protocol_version)
286     {
287      case 1 : info+=sprintf(info,"\nPrtcl: Shareware"); break;
288      case 2 : info+=sprintf(info,"\nPrtcl: Normal"); break;
289      case 3 : info+=sprintf(info,"\nPrtcl: D2X only"); break;
290      case 0 : info+=sprintf(info,"\nPrtcl: D2X hybrid"); break;
291      default: info+=sprintf(info,"\nPrtcl: Unknown"); break;
292     }
293
294    if(game.game_flags & NETGAME_FLAG_SHOW_MAP)
295            info+=sprintf(info,"\n Players on Map");
296    //edited 04/19/99 Matt Mueller - check protocol_ver too.
297    if (game.protocol_version==MULTI_PROTO_D2X_VER 
298 #ifndef SHAREWARE
299 && game.subprotocol>=1
300 #endif
301 ){
302 #ifndef SHAREWARE
303            int i=0,b=0;
304            char sep0=':';
305            if(game.flags & NETFLAG_ENABLE_RADAR)
306                    info+=sprintf(info,"\n Radar");
307            if(game.flags & NETFLAG_ENABLE_ALT_VULCAN)
308                    info+=sprintf(info,"\n Alt Vulcan");
309            info+=sprintf(info,"\n Banned");
310 #define NETFLAG_SHOW_BANNED(D,V) if (!(game.flags&NETFLAG_DO ## D)) {if (i>3) i=0; else i++; info+=sprintf(info,"%c %s",i?sep0:'\n',#V);b++;sep0=',';}
311            NETFLAG_SHOW_BANNED(LASER,laser);
312            NETFLAG_SHOW_BANNED(QUAD,quad);
313            NETFLAG_SHOW_BANNED(VULCAN,vulcan);
314            NETFLAG_SHOW_BANNED(SPREAD,spread);
315            NETFLAG_SHOW_BANNED(PLASMA,plasma);
316            NETFLAG_SHOW_BANNED(FUSION,fusion);
317            NETFLAG_SHOW_BANNED(HOMING,homing);
318            NETFLAG_SHOW_BANNED(SMART,smart);
319            NETFLAG_SHOW_BANNED(MEGA,mega);
320            NETFLAG_SHOW_BANNED(PROXIM,proxim);
321            NETFLAG_SHOW_BANNED(CLOAK,cloak);
322            NETFLAG_SHOW_BANNED(INVUL,invuln);
323            if (b==0) info+=sprintf(info,": none");
324 #endif /* ! SHAREWARE */
325    }
326    //end edit -MM
327  //end edit -MM
328         if (awesomeflag){
329                 int c;
330                 while (1){
331                         c=nm_messagebox("Stats", 3, "Players","Scores","Join Game", rinfo);
332                         if (c==0)
333                                 show_game_players(game, players);
334                         else if (c==1)
335                                 show_game_score(game, players);
336                         else if (c==2)
337                                 return 1;
338                         else
339                                 return 0;
340                 }
341         }else{
342            nm_messagebox("Stats", 1, TXT_OK, rinfo);
343            return 0;
344         }
345 }
346 //end this section addition - Victor Rachels
347
348 //added on 11/12/98 by Victor Rachels to maybe fix some bugs
349 void alphanumize(char *string, int length);
350
351 void alphanumize(char *string, int length)
352 {
353  int i=0;
354   while(i<length && string[i])
355    {
356      if(!((string[i]<=122&&string[i]>=97) ||
357           (string[i]<=90 &&string[i]>=65) ||
358           (string[i]<=57 &&string[i]>=48) ||
359           (string[i]=='\n') ||
360           (string[i]==' ')  ||
361           (string[i]=='-')
362           ) )
363       string[i] = '_';
364     i++;
365    }
366 }
367
368 //added on 10/12/98 by Victor Rachels to show netgamelist scores
369 void show_game_score(netgame_info game, AllNetPlayers_info players)
370 {
371  char scores[2176]="",info[2048]="",deaths[128]="",tmp[10];
372  int i,j,k;
373
374   strcat(scores,"Pilots ");
375   strcat(deaths,"    ");
376
377    for(i=0;i<game.numplayers;i++)
378     if(players.players[i].connected)
379      {
380        strcat(scores,"     ");
381        sprintf(tmp,"%c",players.players[i].callsign[0]);
382        strcat(scores,tmp);
383        strcat(info,players.players[i].callsign);
384         for(k=strlen(players.players[i].callsign);k<9;k++)
385          strcat(info," ");
386         for(j=0;j<game.numplayers;j++)
387          if(players.players[j].connected)
388           {
389            if(i==j&&game.kills[i][j]>0)
390             {
391              strcat(info,"  ");
392              sprintf(tmp,"-%i",game.kills[i][j]);
393             }
394            else
395             {
396              strcat(info,"   ");
397              sprintf(tmp,"%i",game.kills[i][j]);
398             }
399            strcat(info,tmp);
400             for(k=strlen(tmp);k<3;k++)
401              strcat(info," ");
402           }
403        sprintf(tmp,"     %i",game.player_kills[i]);
404        strcat(info,tmp);
405        strcat(info,"\n\n");
406        sprintf(tmp,"     %i",game.killed[i]);
407        strcat(deaths,tmp);
408      }
409   strcat(scores,"   Total\n\n");
410   strcat(scores,info);
411   strcat(deaths,"   \n\n");
412   strcat(scores,deaths);
413   alphanumize(scores,sizeof(scores));
414   nm_messagebox_fixedfont("Score\n", 1, TXT_OK, scores);
415 }
416 //end this section addition - Victor Rachels
417
418 //added on 2000/01/29 by Matt Mueller for direct ip join.
419 #include "netpkt.h"
420 int network_do_join_game(netgame_info *jgame);
421 int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address){
422         sequence_packet me;
423         fix nextsend;
424         int numsent;
425         fix curtime;
426
427         if (setjmp(LeaveGame))
428                 return 0;
429     num_active_games = 0;
430         Network_games_changed = 0;
431         Network_status = NETSTAT_BROWSING;
432     memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
433
434         nextsend=0;numsent=0;
435
436         while (1){
437                 curtime=timer_get_fixed_seconds();
438                 if (nextsend<curtime){
439                         if (numsent>=5)
440                                 return 0;//timeout
441                         nextsend=curtime+F1_0*3;
442                         numsent++;
443                         mprintf((0, "Sending game_list request.\n"));
444                         memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
445                         memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
446                         memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
447                         me.type = PID_D2X_GAME_INFO_REQ;//get full info.
448
449                         send_sequence_packet( me, server,node,net_address);
450                 }
451
452                 network_listen();
453
454                 if (Network_games_changed){
455                         if (num_active_games<1){
456                                 Network_games_changed=0;
457                                 continue;
458                         }
459                         if (show_game_stats(Active_games[0], ActiveNetPlayers[0], 1))
460                                 return (network_do_join_game(&Active_games[0]));
461                         else
462                                 return 0;
463                 }
464                 if (key_inkey()==KEY_ESC)
465                         return 0;
466
467         }
468         return 0;
469 }
470 //end addition -MM
471
472 //added on 1/5/99 by Victor Rachels for missiondir
473 void change_missiondir()
474 {
475  newmenu_item m[1];
476  int i=1;
477  char thogdir[64];
478
479   sprintf(thogdir,AltHogDir);
480
481   m[0].type = NM_TYPE_INPUT; m[0].text = thogdir; m[0].text_len = 64;
482
483   i=newmenu_do1(NULL, "Mission Directory", 1, m, NULL, 0);
484
485    if(i==0)
486     {
487      cfile_use_alternate_hogdir(thogdir);
488      sprintf(thogdir,AltHogDir);
489      m[0].text=thogdir;
490     }
491 }
492 //end this section addition - VR
493
494 //added/changed on 9/17/98 by Victor Rachels for netgame info screen redraw
495 //this was mostly a bunch of random moves and copies from the main function
496 //if you can figure this out more elegantly, go for it.
497 void netlist_redraw(bkg bg,
498                     char menu_text[MAX_ACTIVE_NETGAMES][LINE_ITEMS][MAX_TEXT_LEN],
499                     struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS])
500 {
501  int i,j,k,yp;
502
503         gr_set_current_canvas( NULL );
504
505         init_background(&bg, 0, 7, grd_curcanv->cv_bitmap.bm_w,
506          grd_curcanv->cv_bitmap.bm_h - 14);
507
508         yp=22;
509         gr_set_curfont(Gamefonts[GFONT_BIG_1]);
510         gr_string(0x8000, yp, "Netgames");//yp was 22
511         yp+=grd_curcanv->cv_font->ft_h+network_menu_hskip*3+Gamefonts[GFONT_SMALL]->ft_h;//need to account for size of current socket, drawn elsewhere
512         // draw titles
513         gr_set_curfont(Gamefonts[GFONT_SMALL]);
514         gr_set_fontcolor(BM_XRGB(27, 27, 27), -1);
515         k = 15;
516         for (j = 0; j < LINE_ITEMS; j++) {
517                 gr_ustring(k, yp, network_menu_title[j]);//yp was 61
518                 k += network_menu_width[j];
519         }
520         
521
522         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
523                 struct line_item *li = lis[i];
524                 k=15;
525
526                 yp+=grd_curcanv->cv_font->ft_h+network_menu_hskip;
527                 for (j = 0; j < LINE_ITEMS; j++) {
528                         li[j].x = k;
529                         li[j].y = yp;
530                         //                      li[j].y = 70 + i * 9;
531                         li[j].width = network_menu_width[j] - (j > 1 ? 4 : 0); // HACK!
532                         k += network_menu_width[j];
533                         li[j].value = menu_text[i][j];
534                 }
535                 sprintf(li[0].value, "%d.", i + 1); 
536         }
537
538 }
539 //end this section addition - Victor Rachels
540
541 int network_join_game_menu() {
542         char menu_text[MAX_ACTIVE_NETGAMES][LINE_ITEMS][MAX_TEXT_LEN];
543         struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS];
544         int k;
545         int old_select, old_socket, done, last_num_games;
546         grs_canvas * save_canvas;
547         grs_font * save_font;
548         bkg bg;
549         fix t, req_timer = 0;
550         
551         selected_game = 0;
552         gr_palette_fade_in( gr_palette, 32, 0 );
553         save_canvas = grd_curcanv;
554         gr_set_current_canvas( NULL );
555         save_font = grd_curcanv->cv_font;
556         
557         for (k=0;k<LINE_ITEMS;k++)//scale columns to fit screen res.
558                 network_menu_width[k]=ref_network_menu_width[k]*grd_curcanv->cv_bitmap.bm_w/320;
559         network_menu_hskip=(grd_curcanv->cv_bitmap.bm_h-Gamefonts[GFONT_BIG_1]->ft_h-22-Gamefonts[GFONT_SMALL]->ft_h*17)/17;
560
561         init_background(&bg, 0, 7, grd_curcanv->cv_bitmap.bm_w,
562          grd_curcanv->cv_bitmap.bm_h - 14);
563
564         game_flush_inputs();
565
566 //added/changed on 9/17/98 by Victor Rachels for netgame info screen redraw
567         netlist_redraw(bg,menu_text,lis);
568 //end this section addition - Victor Rachels
569
570         Network_games_changed = 1;
571         old_socket = -32768;
572         old_select = -1;
573         last_num_games = 0;
574         if ( gr_palette_faded_out ) {
575             gr_palette_fade_in( gr_palette, 32, 0 );
576         }
577
578         done = 0;
579
580         while (!done) {
581                 if (Network_socket != old_socket) {
582                         gr_set_fontcolor(BM_XRGB(27, 27, 27), -1);
583                         draw_back(&bg, 30, 22+Gamefonts[GFONT_BIG_1]->ft_h+network_menu_hskip*2, 250, Gamefonts[GFONT_SMALL]->ft_h+4);//was 52,250,9
584                         gr_printf(30, 22+Gamefonts[GFONT_BIG_1]->ft_h+network_menu_hskip*2, "Current IPX socket is %+d "
585                                         "(PgUp/PgDn to change)", Network_socket);
586                         if (old_socket != -32768) { /* changed by user? */
587                                 network_listen();
588                                 ipx_change_default_socket( IPX_DEFAULT_SOCKET + Network_socket );
589                                 num_active_games = 0;
590                         }
591                         req_timer -= F1_0 * 5; /* force send request */
592                         Network_games_changed = 1;
593                 }
594                 if (Network_games_changed) {
595                         if (num_active_games > last_num_games) /* new game? */
596                                 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
597                         last_num_games = num_active_games;
598                         Network_games_changed = 0;
599                         draw_list(&bg, lis);
600                         //added on 9/13/98 by adb to make update-needing arch's work
601                         gr_update();
602                         //end addition - adb
603
604                 } else if (selected_game != old_select) {
605                         draw_item(&bg, lis[old_select], 0);
606                         draw_item(&bg, lis[selected_game], 1);
607                         //added on 9/13/98 by adb to make update-needing arch's work
608                         gr_update();
609                         //end addition - adb
610                 }
611                 old_socket = Network_socket;
612                 old_select = selected_game;
613
614                 t = timer_get_approx_seconds();
615                 if (t < req_timer || t > req_timer + F1_0 * 5) {
616                         req_timer = timer_get_approx_seconds();
617                         network_send_game_list_request();
618                 }                               
619                 network_listen();
620
621                 k = key_inkey();
622                 switch (k) {
623 //added 9/16-17/98 by Victor Rachels for netgamelist info
624         //edit 4/18/99 Matt Mueller - use KEY_? defines so it actually works on non-dos
625                         case KEY_U: //U = 0x16
626                                 if(selected_game<num_active_games)
627                                  {
628                                    show_game_players(Active_games[selected_game], ActiveNetPlayers[selected_game]);
629                                    netlist_redraw(bg,menu_text,lis);
630                                    old_socket = -32768;
631                                    old_select = -1;
632                                  }
633                                 break;
634                         case KEY_I: //I = 0x17
635                                 if(selected_game<num_active_games)
636                                  {
637                                    show_game_stats(Active_games[selected_game], ActiveNetPlayers[selected_game], 0);
638                                    netlist_redraw(bg,menu_text,lis);
639                                    old_socket = -32768;
640                                    old_select = -1;
641                                  }
642                                 break;
643 //end this section addition - Victor
644 //added 10/12/98 by Victor Rachels for netgamelist scores
645                         case  KEY_S: //S = 0x1f
646                                 if(selected_game<num_active_games)
647                                  {
648                                   show_game_score(Active_games[selected_game], ActiveNetPlayers[selected_game]);
649                                   netlist_redraw(bg,menu_text,lis);
650                                   old_socket = -32768;
651                                   old_select = -1;
652                                  }
653                                 break;
654 //end this section addition - Victor
655                         case KEY_M: //M = 0x32
656         //end edit -MM
657                                  {
658                                   change_missiondir();
659                                   netlist_redraw(bg,menu_text,lis);
660                                   old_socket = -32768;
661                                   old_select = -1;
662                                  }
663                         case KEY_PAGEUP:
664                         case KEY_PAD9:
665                                 if (Network_socket < 99) Network_socket++;
666                                 break;
667                         case KEY_PAGEDOWN:
668                         case KEY_PAD3:
669                                 if (Network_socket > -99) Network_socket--;
670                                 break;
671                         case KEY_PAD5:
672                                 Network_socket = 0;
673                                 break;
674                         case KEY_TAB + KEY_SHIFTED:
675                         case KEY_UP:
676                         case KEY_PAD8:
677                                 if (selected_game-- == 0)
678                                         selected_game = MAX_ACTIVE_NETGAMES - 1;
679                                 break;
680                         case KEY_TAB:
681                         case KEY_DOWN:
682                         case KEY_PAD2:
683                                 if (++selected_game == MAX_ACTIVE_NETGAMES)
684                                         selected_game = 0;
685                                 break;
686                         case KEY_ENTER:
687                         case KEY_PADENTER:
688                                 done = 1;
689                                 break;
690 #if 0
691                         //added on 11/20/99 by Victor Rachels to add observer mode
692                         case KEY_O:
693                                 I_am_observer=1;
694                                 done = 1;
695                                 break;
696                         //end this section addition - VR
697 #endif
698                         case KEY_ESC:
699                                 selected_game = -1;
700                                 done = 1;
701                                 break;
702                         case KEYS_GR_TOGGLE_FULLSCREEN:
703                                 gr_toggle_fullscreen_menu();
704                                 break;
705                 }
706         }
707     done_background(&bg);
708         //edited 05/18/99 Matt Mueller - restore the font *after* the canvas, or else we are writing into the free'd memory
709         gr_set_current_canvas( save_canvas );
710         grd_curcanv->cv_font = save_font;
711         //end edit -MM
712         return selected_game;
713 }