2 * $Source: /cvs/cvsroot/d2x/main/netlist.c,v $
5 * $Date: 2002-02-14 10:18:24 $
7 * Descent II-a-like network game join menu
10 * $Log: not supported by cvs2svn $
11 * Revision 1.2 2002/02/14 09:24:19 bradleyb
14 * Revision 1.1 2002/02/14 09:05:33 bradleyb
15 * Lotsa networking stuff from d1x
42 //added 4/18/99 Matt Mueller - show radar in game info
51 //added on 1/5/99 by Victor Rachels for missiondir
53 //end this section addition
56 #define MAX_TEXT_LEN 25
58 extern int Network_games_changed;
59 extern netgame_info Active_games[MAX_ACTIVE_NETGAMES];
60 extern AllNetPlayers_info ActiveNetPlayers[MAX_ACTIVE_NETGAMES];
61 extern int num_active_games;
62 extern int Network_socket;
63 void network_listen();
64 void network_send_game_list_request();
66 void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest);
69 grs_canvas * menu_canvas;
70 grs_bitmap * saved; // The background under the menu.
71 grs_bitmap * background;
72 int background_is_sub;
75 extern grs_bitmap nm_background;
83 void network_draw_game(const netgame_info *game) {
86 char *network_mode_text(const netgame_info *game) {
87 //edit 4/18/99 Matt Mueller - GTEAM? heh. Should be "TEAM" I think.
88 static char *names[4]={"ANRCHY", "TEAM", "ROBO", "COOP"};
91 if (game->gamemode >= 4 ||
92 (game->protocol_version != MULTI_PROTO_VERSION &&
93 (game->protocol_version != MULTI_PROTO_D2X_VER ||
94 game->required_subprotocol > MULTI_PROTO_D2X_MINOR)))
97 return names[game->gamemode];
100 char *network_status_text(const netgame_info *game, int activeplayers) {
101 switch (game->game_status) {
102 case NETSTAT_STARTING:
104 case NETSTAT_PLAYING:
105 if (game->game_flags & NETGAME_FLAG_CLOSED)
107 else if (activeplayers == game->max_numplayers)
116 static void network_update_item(const netgame_info *game, const AllNetPlayers_info *players, struct line_item li[]) {
117 int i, activeplayers = 0;
118 // get number of active players
119 for (i = 0; i < game->numplayers; i++)
120 if (players->players[i].connected)
122 strcpy(li[1].value, game->protocol_version == MULTI_PROTO_D2X_VER ? "+" : "");
123 strcpy(li[2].value, game->game_name);
124 strcpy(li[3].value, network_mode_text(game));
126 sprintf(li[4].value, "%d/%d", activeplayers, game->max_numplayers);
128 strcpy(li[5].value, game->mission_title);
130 strcpy(li[5].value, "Descent: First Strike");
132 if (game->levelnum < 0)
133 sprintf(li[6].value, "S%d", -game->levelnum);
135 sprintf(li[6].value, "%d", game->levelnum);
136 strcpy(li[7].value, network_status_text(game, activeplayers));
139 static void update_items(struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS]) {
142 for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
143 if (i >= num_active_games) {
144 for (j = 1; j < LINE_ITEMS; j++)
145 lis[i][j].value[0] = 0;
147 network_update_item(&Active_games[i], &ActiveNetPlayers[i], lis[i]);
151 int network_menu_hskip=4;
152 int network_menu_width[LINE_ITEMS] = { 10, 6, 72, 37, 38, 66, 25, 40 };
153 int ref_network_menu_width[LINE_ITEMS] = { 10, 6, 72, 37, 38, 66, 25, 40 };
154 char *network_menu_title[LINE_ITEMS] = { "", "", "Game", "Mode", "#Plrs", "Mission", "Lev", "Status" };
156 static int selected_game;
158 static void draw_back(bkg *b, int x, int y, int w, int h) {
159 gr_bm_bitblt(b->background->bm_w-15, h, 5, y, 5, y, b->background, &(grd_curcanv->cv_bitmap) );
162 static void draw_item(bkg *b, struct line_item *li, int is_current) {
163 int i, w, h, aw, max_w, pad_w, y;
164 char str[MAX_TEXT_LEN], *p;
168 gr_set_fontcolor(BM_XRGB(31, 27, 6), -1);
170 gr_set_fontcolor(BM_XRGB(17, 17, 26), -1);
171 gr_get_string_size(" ...", &pad_w, &h, &aw);
172 draw_back(b, li[0].x, y,
173 li[LINE_ITEMS-1].x + li[LINE_ITEMS-1].width - li[0].x, h);
174 for (i = 0; i < LINE_ITEMS; i++) {
175 strcpy(str, li[i].value);
176 gr_get_string_size(str, &w, &h, &aw);
177 if (w > li[i].width) {
178 max_w = li[i].width - pad_w;
179 p = str + strlen(str);
180 while (p > str && w > max_w) {
182 gr_get_string_size(str, &w, &h, &aw);
186 gr_ustring(li[i].x, y, str);
190 static void draw_list(bkg *bg,
191 struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS]) {
194 for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
195 draw_item(bg, lis[i], i == selected_game);
198 static void init_background(bkg *bg, int x, int y, int w, int h) {
199 bg->menu_canvas = gr_create_sub_canvas( &grd_curscreen->sc_canvas, x, y, w, h );
200 gr_set_current_canvas( bg->menu_canvas );
202 // Save the background under the menu...
203 bg->saved = gr_create_bitmap( w, h );
204 Assert( bg->saved != NULL );
205 gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg->saved );
206 gr_set_current_canvas( NULL );
207 nm_draw_background(x,y,x+w-1,y+h-1);
208 if (w > nm_background.bm_w || h > nm_background.bm_h){
209 bg->background=gr_create_bitmap(w,h);
210 gr_bitmap_scale_to(&nm_background,bg->background);
211 bg->background_is_sub=0;
213 bg->background = gr_create_sub_bitmap(&nm_background,0,0,w,h);
214 bg->background_is_sub=1;
216 gr_set_current_canvas( bg->menu_canvas );
219 static void done_background(bkg *bg) {
220 gr_set_current_canvas(bg->menu_canvas);
221 gr_bitmap(0, 0, bg->saved);
222 gr_free_bitmap(bg->saved);
223 if (bg->background_is_sub)
224 gr_free_sub_bitmap( bg->background );
226 gr_free_bitmap( bg->background );
227 gr_free_sub_canvas( bg->menu_canvas );
231 //added on 9/16-18/98 by Victor Rachels to add info boxes to netgameslist
232 void show_game_players(netgame_info game, AllNetPlayers_info players)
234 char pilots[(CALLSIGN_LEN+2)*MAX_PLAYERS];
237 memset(pilots,0,sizeof(char)*(CALLSIGN_LEN+2)*MAX_PLAYERS);
239 for(i=0;i<game.numplayers;i++)
240 if(players.players[i].connected)
242 strcat(pilots,players.players[i].callsign);
246 nm_messagebox("Players", 1, TXT_OK, pilots);
249 void show_game_score(netgame_info game, AllNetPlayers_info players);
251 int show_game_stats(netgame_info game, AllNetPlayers_info players, int awesomeflag)
253 //edited 4/18/99 Matt Mueller - show radar flag and banned stuff too
254 //switched to the info/rinfo mode to 1)allow sprintf easily 2) save some
255 //cpu cycles not seeking to the end of the string each time.
256 char rinfo[512],*info=rinfo;
258 memset(info,0,sizeof(char)*256);
261 if(!game.mission_name)
263 info+=sprintf(info,"Level: Descent: First Strike");
266 info+=sprintf(info,game.mission_name);
269 switch(game.gamemode)
271 case 0 : info+=sprintf(info,"\nMode: Anarchy"); break;
272 case 1 : info+=sprintf(info,"\nMode: Team"); break;
273 case 2 : info+=sprintf(info,"\nMode: Robo"); break;
274 case 3 : info+=sprintf(info,"\nMode: Coop"); break;
275 default: info+=sprintf(info,"\nMode: Unknown"); break;
278 switch(game.difficulty)
280 case 0 : info+=sprintf(info,"\nDiff: Trainee"); break;
281 case 1 : info+=sprintf(info,"\nDiff: Rookie"); break;
282 case 2 : info+=sprintf(info,"\nDiff: Hotshot"); break;
283 case 3 : info+=sprintf(info,"\nDiff: Ace"); break;
284 case 4 : info+=sprintf(info,"\nDiff: Insane"); break;
285 default: info+=sprintf(info,"\nDiff: Unknown"); break;
288 switch(game.protocol_version)
290 case 1 : info+=sprintf(info,"\nPrtcl: Shareware"); break;
291 case 2 : info+=sprintf(info,"\nPrtcl: Normal"); break;
292 case 3 : info+=sprintf(info,"\nPrtcl: D2X only"); break;
293 case 0 : info+=sprintf(info,"\nPrtcl: D2X hybrid"); break;
294 default: info+=sprintf(info,"\nPrtcl: Unknown"); break;
297 if(game.game_flags & NETGAME_FLAG_SHOW_MAP)
298 info+=sprintf(info,"\n Players on Map");
299 //edited 04/19/99 Matt Mueller - check protocol_ver too.
300 if (game.protocol_version==MULTI_PROTO_D2X_VER
302 && game.subprotocol>=1
308 if(game.flags & NETFLAG_ENABLE_RADAR)
309 info+=sprintf(info,"\n Radar");
310 if(game.flags & NETFLAG_ENABLE_ALT_VULCAN)
311 info+=sprintf(info,"\n Alt Vulcan");
312 info+=sprintf(info,"\n Banned");
313 #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=',';}
314 NETFLAG_SHOW_BANNED(LASER,laser);
315 NETFLAG_SHOW_BANNED(QUAD,quad);
316 NETFLAG_SHOW_BANNED(VULCAN,vulcan);
317 NETFLAG_SHOW_BANNED(SPREAD,spread);
318 NETFLAG_SHOW_BANNED(PLASMA,plasma);
319 NETFLAG_SHOW_BANNED(FUSION,fusion);
320 NETFLAG_SHOW_BANNED(HOMING,homing);
321 NETFLAG_SHOW_BANNED(SMART,smart);
322 NETFLAG_SHOW_BANNED(MEGA,mega);
323 NETFLAG_SHOW_BANNED(PROXIM,proxim);
324 NETFLAG_SHOW_BANNED(CLOAK,cloak);
325 NETFLAG_SHOW_BANNED(INVUL,invuln);
326 if (b==0) info+=sprintf(info,": none");
327 #endif /* ! SHAREWARE */
334 c=nm_messagebox("Stats", 3, "Players","Scores","Join Game", rinfo);
336 show_game_players(game, players);
338 show_game_score(game, players);
345 nm_messagebox("Stats", 1, TXT_OK, rinfo);
349 //end this section addition - Victor Rachels
351 //added on 11/12/98 by Victor Rachels to maybe fix some bugs
352 void alphanumize(char *string, int length);
354 void alphanumize(char *string, int length)
357 while(i<length && string[i])
359 if(!((string[i]<=122&&string[i]>=97) ||
360 (string[i]<=90 &&string[i]>=65) ||
361 (string[i]<=57 &&string[i]>=48) ||
371 //added on 10/12/98 by Victor Rachels to show netgamelist scores
372 void show_game_score(netgame_info game, AllNetPlayers_info players)
374 char scores[2176]="",info[2048]="",deaths[128]="",tmp[10];
377 strcat(scores,"Pilots ");
380 for(i=0;i<game.numplayers;i++)
381 if(players.players[i].connected)
384 sprintf(tmp,"%c",players.players[i].callsign[0]);
386 strcat(info,players.players[i].callsign);
387 for(k=strlen(players.players[i].callsign);k<9;k++)
389 for(j=0;j<game.numplayers;j++)
390 if(players.players[j].connected)
392 if(i==j&&game.kills[i][j]>0)
395 sprintf(tmp,"-%i",game.kills[i][j]);
400 sprintf(tmp,"%i",game.kills[i][j]);
403 for(k=strlen(tmp);k<3;k++)
406 sprintf(tmp," %i",game.player_kills[i]);
409 sprintf(tmp," %i",game.killed[i]);
412 strcat(scores," Total\n\n");
414 strcat(deaths," \n\n");
415 strcat(scores,deaths);
416 alphanumize(scores,sizeof(scores));
417 nm_messagebox_fixedfont("Score\n", 1, TXT_OK, scores);
419 //end this section addition - Victor Rachels
421 //added on 2000/01/29 by Matt Mueller for direct ip join.
423 int network_do_join_game(netgame_info *jgame);
424 int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address){
430 if (setjmp(LeaveGame))
432 num_active_games = 0;
433 Network_games_changed = 0;
434 Network_status = NETSTAT_BROWSING;
435 memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
437 nextsend=0;numsent=0;
440 curtime=timer_get_fixed_seconds();
441 if (nextsend<curtime){
444 nextsend=curtime+F1_0*3;
446 mprintf((0, "Sending game_list request.\n"));
447 memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
448 memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
449 memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
450 me.type = PID_D2X_GAME_INFO_REQ;//get full info.
452 send_sequence_packet( me, server,node,net_address);
457 if (Network_games_changed){
458 if (num_active_games<1){
459 Network_games_changed=0;
462 if (show_game_stats(Active_games[0], ActiveNetPlayers[0], 1))
463 return (network_do_join_game(&Active_games[0]));
467 if (key_inkey()==KEY_ESC)
475 //added on 1/5/99 by Victor Rachels for missiondir
476 void change_missiondir()
482 sprintf(thogdir,AltHogDir);
484 m[0].type = NM_TYPE_INPUT; m[0].text = thogdir; m[0].text_len = 64;
486 i=newmenu_do1(NULL, "Mission Directory", 1, m, NULL, 0);
490 cfile_use_alternate_hogdir(thogdir);
491 sprintf(thogdir,AltHogDir);
495 //end this section addition - VR
497 //added/changed on 9/17/98 by Victor Rachels for netgame info screen redraw
498 //this was mostly a bunch of random moves and copies from the main function
499 //if you can figure this out more elegantly, go for it.
500 void netlist_redraw(bkg bg,
501 char menu_text[MAX_ACTIVE_NETGAMES][LINE_ITEMS][MAX_TEXT_LEN],
502 struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS])
506 gr_set_current_canvas( NULL );
508 init_background(&bg, 0, 7, grd_curcanv->cv_bitmap.bm_w,
509 grd_curcanv->cv_bitmap.bm_h - 14);
512 gr_set_curfont(Gamefonts[GFONT_BIG_1]);
513 gr_string(0x8000, yp, "Netgames");//yp was 22
514 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
516 gr_set_curfont(Gamefonts[GFONT_SMALL]);
517 gr_set_fontcolor(BM_XRGB(27, 27, 27), -1);
519 for (j = 0; j < LINE_ITEMS; j++) {
520 gr_ustring(k, yp, network_menu_title[j]);//yp was 61
521 k += network_menu_width[j];
525 for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
526 struct line_item *li = lis[i];
529 yp+=grd_curcanv->cv_font->ft_h+network_menu_hskip;
530 for (j = 0; j < LINE_ITEMS; j++) {
533 // li[j].y = 70 + i * 9;
534 li[j].width = network_menu_width[j] - (j > 1 ? 4 : 0); // HACK!
535 k += network_menu_width[j];
536 li[j].value = menu_text[i][j];
538 sprintf(li[0].value, "%d.", i + 1);
542 //end this section addition - Victor Rachels
544 int network_join_game_menu() {
545 char menu_text[MAX_ACTIVE_NETGAMES][LINE_ITEMS][MAX_TEXT_LEN];
546 struct line_item lis[MAX_ACTIVE_NETGAMES][LINE_ITEMS];
548 int old_select, old_socket, done, last_num_games;
549 grs_canvas * save_canvas;
550 grs_font * save_font;
552 fix t, req_timer = 0;
555 gr_palette_fade_in( gr_palette, 32, 0 );
556 save_canvas = grd_curcanv;
557 gr_set_current_canvas( NULL );
558 save_font = grd_curcanv->cv_font;
560 for (k=0;k<LINE_ITEMS;k++)//scale columns to fit screen res.
561 network_menu_width[k]=ref_network_menu_width[k]*grd_curcanv->cv_bitmap.bm_w/320;
562 network_menu_hskip=(grd_curcanv->cv_bitmap.bm_h-Gamefonts[GFONT_BIG_1]->ft_h-22-Gamefonts[GFONT_SMALL]->ft_h*17)/17;
564 init_background(&bg, 0, 7, grd_curcanv->cv_bitmap.bm_w,
565 grd_curcanv->cv_bitmap.bm_h - 14);
569 //added/changed on 9/17/98 by Victor Rachels for netgame info screen redraw
570 netlist_redraw(bg,menu_text,lis);
571 //end this section addition - Victor Rachels
573 Network_games_changed = 1;
577 if ( gr_palette_faded_out ) {
578 gr_palette_fade_in( gr_palette, 32, 0 );
584 if (Network_socket != old_socket) {
585 gr_set_fontcolor(BM_XRGB(27, 27, 27), -1);
586 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
587 gr_printf(30, 22+Gamefonts[GFONT_BIG_1]->ft_h+network_menu_hskip*2, "Current IPX socket is %+d "
588 "(PgUp/PgDn to change)", Network_socket);
589 if (old_socket != -32768) { /* changed by user? */
591 ipx_change_default_socket( IPX_DEFAULT_SOCKET + Network_socket );
592 num_active_games = 0;
594 req_timer -= F1_0 * 5; /* force send request */
595 Network_games_changed = 1;
597 if (Network_games_changed) {
598 if (num_active_games > last_num_games) /* new game? */
599 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
600 last_num_games = num_active_games;
601 Network_games_changed = 0;
603 //added on 9/13/98 by adb to make update-needing arch's work
607 } else if (selected_game != old_select) {
608 draw_item(&bg, lis[old_select], 0);
609 draw_item(&bg, lis[selected_game], 1);
610 //added on 9/13/98 by adb to make update-needing arch's work
614 old_socket = Network_socket;
615 old_select = selected_game;
617 t = timer_get_approx_seconds();
618 if (t < req_timer || t > req_timer + F1_0 * 5) {
619 req_timer = timer_get_approx_seconds();
620 network_send_game_list_request();
626 //added 9/16-17/98 by Victor Rachels for netgamelist info
627 //edit 4/18/99 Matt Mueller - use KEY_? defines so it actually works on non-dos
628 case KEY_U: //U = 0x16
629 if(selected_game<num_active_games)
631 show_game_players(Active_games[selected_game], ActiveNetPlayers[selected_game]);
632 netlist_redraw(bg,menu_text,lis);
637 case KEY_I: //I = 0x17
638 if(selected_game<num_active_games)
640 show_game_stats(Active_games[selected_game], ActiveNetPlayers[selected_game], 0);
641 netlist_redraw(bg,menu_text,lis);
646 //end this section addition - Victor
647 //added 10/12/98 by Victor Rachels for netgamelist scores
648 case KEY_S: //S = 0x1f
649 if(selected_game<num_active_games)
651 show_game_score(Active_games[selected_game], ActiveNetPlayers[selected_game]);
652 netlist_redraw(bg,menu_text,lis);
657 //end this section addition - Victor
658 case KEY_M: //M = 0x32
662 netlist_redraw(bg,menu_text,lis);
668 if (Network_socket < 99) Network_socket++;
672 if (Network_socket > -99) Network_socket--;
677 case KEY_TAB + KEY_SHIFTED:
680 if (selected_game-- == 0)
681 selected_game = MAX_ACTIVE_NETGAMES - 1;
686 if (++selected_game == MAX_ACTIVE_NETGAMES)
694 //added on 11/20/99 by Victor Rachels to add observer mode
699 //end this section addition - VR
705 case KEY_CTRLED+KEY_SHIFTED+KEY_PADENTER:
706 case KEY_ALTED+KEY_CTRLED+KEY_PADENTER:
707 case KEY_ALTED+KEY_SHIFTED+KEY_PADENTER:
708 gr_toggle_fullscreen_menu();
712 done_background(&bg);
713 //edited 05/18/99 Matt Mueller - restore the font *after* the canvas, or else we are writing into the free'd memory
714 gr_set_current_canvas( save_canvas );
715 grd_curcanv->cv_font = save_font;
717 return selected_game;