changed args_find to FindArg
[btb/d2x.git] / main / network.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #ifdef RCS
15 static char rcsid[] = "$Id: network.c,v 1.3 2001-01-24 04:29:45 bradleyb Exp $";
16 #endif
17
18 #include <conf.h>
19
20 #ifdef NETWORK
21
22 #define PATCH12
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27
28 #include "pstypes.h"
29 #include "strutil.h"
30 #include "args.h"
31 #include "timer.h"
32 #include "mono.h"
33 #include "ipx.h"
34 #include "newmenu.h"
35 #include "key.h"
36 #include "gauges.h"
37 #include "object.h"
38 #include "error.h"
39 #include "laser.h"
40 #include "gamesave.h"
41 #include "gamemine.h"
42 #include "player.h"
43 #include "gameseq.h"
44 #include "fireball.h"
45 #include "network.h"
46 #include "game.h"
47 #include "multi.h"
48 #include "endlevel.h"
49 #include "palette.h"
50 #include "cntrlcen.h"
51 #include "powerup.h"
52 #include "menu.h"
53 #include "sounds.h"
54 #include "text.h"
55 #include "kmatrix.h"
56 #include "newdemo.h"
57 #include "multibot.h"
58 #include "wall.h"
59 #include "bm.h"
60 #include "effects.h"
61 #include "physics.h"
62 #include "switch.h"
63 #include "automap.h"
64 #include "byteswap.h"
65 #include "netmisc.h"
66 #include "kconfig.h"
67 #include "playsave.h"
68
69 #ifdef MACINTOSH
70 #include <Events.h>
71 #include <Errors.h>             // for appletalk networking errors
72 #include "appltalk.h"
73 #endif
74
75 void network_send_rejoin_sync(int player_num);
76 void network_update_netgame(void);
77 void network_read_endlevel_packet( ubyte *data );
78 void network_read_object_packet( ubyte *data );
79 void network_read_sync_packet( netgame_info * sp, int d1x );
80 void network_flush();
81 void network_listen();
82 void network_read_pdata_packet(frame_info *pd );
83
84 void network_check_for_old_version (char pnum);
85 void network_send_endlevel_short_sub(int from_player_num,int to_player);
86 int network_wait_for_playerinfo();
87 void network_process_pdata (char *data);
88 void network_read_endlevel_short_packet( ubyte *data );
89 void network_ping (ubyte flag,int pnum);
90 void network_handle_ping_return (ubyte pnum);
91 void network_process_names_return (char *data);
92 void network_send_player_names (sequence_packet *their);
93 int network_choose_connect ();
94 void network_more_game_options ();
95 void network_count_powerups_in_mine(void);
96 int network_wait_for_all_info (int choice);
97 void network_do_big_wait(int choice);
98 void network_send_extras ();
99 void network_read_pdata_short_packet(short_frame_info *pd );
100
101 void network_AdjustMaxDataSize ();
102
103 void ClipRank (signed char *rank);
104 void DoRefuseStuff (sequence_packet *their);
105 void SetAllAllowablesTo (int on);
106 int GetNewPlayerNumber (sequence_packet *their);
107
108 #define LHX(x)          ((x)*(MenuHires?2:1))
109 #define LHY(y)          ((y)*(MenuHires?2.4:1))
110
111 #define PID_LITE_INFO                           43
112 #define PID_SEND_ALL_GAMEINFO      44
113 #define PID_PLAYERSINFO                         45
114 #define PID_REQUEST                                     46
115 #define PID_SYNC                                                47
116 #define PID_PDATA                                               48
117 #define PID_ADDPLAYER                           49
118 #define PID_DUMP                                                51
119 #define PID_ENDLEVEL                                    52
120 #define PID_QUIT_JOINING                        54
121 #define PID_OBJECT_DATA                         55
122 #define PID_GAME_LIST                           56
123 #define PID_GAME_INFO                           57
124 #define PID_PING_SEND                           58
125 #define PID_PING_RETURN                         59
126 #define PID_GAME_UPDATE                         60
127 #define PID_ENDLEVEL_SHORT                      61
128 #define PID_NAKED_PDATA                         62
129 #define PID_GAME_PLAYERS                                                                63
130 #define PID_NAMES_RETURN                                                                64
131
132 #define NETGAME_ANARCHY                         0
133 #define NETGAME_TEAM_ANARCHY            1
134 #define NETGAME_ROBOT_ANARCHY           2
135 #define NETGAME_COOPERATIVE             3
136 #define NETGAME_CAPTURE_FLAG            4
137 #define NETGAME_HOARD                            5
138 #define NETGAME_TEAM_HOARD                                       6
139
140 #define NETSECURITY_OFF 0
141 #define NETSECURITY_WAIT_FOR_PLAYERS 1
142 #define NETSECURITY_WAIT_FOR_GAMEINFO 2
143 #define NETSECURITY_WAIT_FOR_SYNC 3
144
145 // MWA -- these structures are aligned -- please save me sanity and
146 // headaches by keeping alignment if these are changed!!!!  Contact
147 // me for info.
148
149 typedef struct endlevel_info {
150         ubyte                                   type;
151         ubyte                                   player_num;
152         byte                                    connected;
153         ubyte                                   seconds_left;
154         short                                   kill_matrix[MAX_PLAYERS][MAX_PLAYERS];
155         short                                   kills;
156         short                                   killed;
157 } endlevel_info;
158
159 typedef struct endlevel_info_short {
160         ubyte                                   type;
161         ubyte                                   player_num;
162         byte                                    connected;
163         ubyte                                   seconds_left;
164 } endlevel_info_short;
165
166 // WARNING!!! This is the top part of netgame_info...if that struct changes,
167 //      this struct much change as well.  ie...they are aligned and the join system will
168 // not work without it.
169
170 // MWA  if this structure changes -- please make appropriate changes to receive_netgame_info
171 // code for macintosh in netmisc.c
172
173 typedef struct lite_info {
174         ubyte                           type;
175         int                             Security;
176         char                            game_name[NETGAME_NAME_LEN+1];
177         char                            mission_title[MISSION_NAME_LEN+1];
178         char                            mission_name[9];
179         int                             levelnum;
180         ubyte                           gamemode;
181         ubyte                           RefusePlayers;
182         ubyte                           difficulty;
183         ubyte                           game_status;
184         ubyte                           numplayers;
185         ubyte                           max_numplayers;
186         ubyte                           numconnected;
187         ubyte                           game_flags;
188         ubyte                           protocol_version;
189         ubyte                           version_major;
190         ubyte                           version_minor;
191         ubyte                           team_vector;
192  } lite_info;
193
194 // IF YOU CHANGE THE SIZE OF ANY OF THE FOLLOWING STRUCTURES
195 // MAKE THE MACINTOSH DEFINES BE THE SAME SIZE AS THE PC OR
196 // I WILL HAVE TO HURT YOU VERY BADLY!!!  -- MWA
197
198 #ifdef MACINTOSH
199 #define NETGAME_INFO_SIZE               ( Network_game_type == IPX_GAME?355:sizeof(netgame_info) )
200 #define ALLNETPLAYERSINFO_SIZE  ( Network_game_type == IPX_GAME?317:sizeof(AllNetPlayers_info) )
201 #define LITE_INFO_SIZE                  ( Network_game_type == IPX_GAME?72:sizeof(lite_info) )
202 #define SEQUENCE_PACKET_SIZE    ( Network_game_type == IPX_GAME?34:sizeof(sequence_packet) )
203 #define FRAME_INFO_SIZE                 ( Network_game_type == IPX_GAME?541:sizeof(frame_info) )
204 #define IPX_SHORT_INFO_SIZE             ( 490 )
205 #else
206 #define NETGAME_INFO_SIZE               sizeof(netgame_info)
207 #define ALLNETPLAYERSINFO_SIZE  sizeof(AllNetPlayers_info)
208 #define LITE_INFO_SIZE                  sizeof(lite_info)
209 #define SEQUENCE_PACKET_SIZE    sizeof(sequence_packet)
210 #define FRAME_INFO_SIZE                 sizeof(frame_info)
211 #endif
212
213 #define MAX_ACTIVE_NETGAMES     12
214
215 netgame_info Active_games[MAX_ACTIVE_NETGAMES];
216 AllNetPlayers_info ActiveNetPlayers[MAX_ACTIVE_NETGAMES];
217 AllNetPlayers_info *TempPlayersInfo,TempPlayersBase;
218 int NamesInfoSecurity=-1;
219
220 // MWAnetgame_info *TempNetInfo; 
221 netgame_info TempNetInfo;
222
223 extern void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[]);
224 extern void multi_send_kill_goal_counts();
225 extern int newmenu_dotiny( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem) );
226
227 void network_process_naked_pdata (char *,int);
228 extern void multi_send_robot_controls(char);
229
230 int num_active_games = 0;
231 int PacketsPerSec=10;
232 int MaxXDataSize=NET_XDATA_SIZE;
233
234 int       Netlife_kills=0, Netlife_killed=0;
235
236 int     Network_debug=0;
237 int     Network_active=0;
238
239 int     Network_status = 0;
240 int     Network_games_changed = 0;
241
242 int     Network_socket = 0;
243 int     Network_allow_socket_changes = 1;
244
245 int     NetSecurityFlag=NETSECURITY_OFF;
246 int     NetSecurityNum=0;
247 int       Network_sending_extras=0;
248 int      VerifyPlayerJoined=-1;
249 int       Player_joining_extras=-1;  // This is so we know who to send 'latecomer' packets to.
250                                                                                           // We could just send updates to everyone but that kills the sender!   
251
252 // For rejoin object syncing
253
254 int     Network_rejoined = 0;       // Did WE rejoin this game?
255 int     Network_new_game = 0;            // Is this the first level of a new game?
256 int     Network_send_objects = 0;  // Are we in the process of sending objects to a player?
257 int     Network_send_objnum = -1;   // What object are we sending next?
258 int     Network_player_added = 0;   // Is this a new player or a returning player?
259 int     Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic?
260 sequence_packet Network_player_rejoining; // Who is rejoining now?
261
262 fix     LastPacketTime[MAX_PLAYERS]; // For timeouts of idle/crashed players
263
264 int     PacketUrgent = 0;
265 int   NetGameType=0;
266 int     TotalMissedPackets=0,TotalPacketsGot=0;
267
268 frame_info      MySyncPack,UrgentSyncPack;
269 ubyte           MySyncPackInitialized = 0;              // Set to 1 if the MySyncPack is zeroed.
270 ushort          my_segments_checksum = 0;
271
272 sequence_packet My_Seq;
273 char WantPlayersInfo=0;
274 char WaitingForPlayerInfo=0;
275
276 char *RankStrings[]={"(unpatched) ","Cadet ","Ensign ","Lieutenant ","Lt.Commander ",
277                                                                 "Commander ","Captain ","Vice Admiral ","Admiral ","Demigod "};
278
279 extern obj_position Player_init[MAX_PLAYERS];
280
281 extern int force_cockpit_redraw;
282
283 #define DUMP_CLOSED 0
284 #define DUMP_FULL 1
285 #define DUMP_ENDLEVEL 2
286 #define DUMP_DORK 3
287 #define DUMP_ABORTED 4
288 #define DUMP_CONNECTED 5
289 #define DUMP_LEVEL 6
290 #define DUMP_KICKED 7
291
292 extern ubyte Version_major,Version_minor;
293 extern ubyte SurfingNet;
294 extern char MaxPowerupsAllowed[MAX_POWERUP_TYPES];
295 extern char PowerupsInMine[MAX_POWERUP_TYPES];
296
297 extern void multi_send_stolen_items();
298
299 int network_wait_for_snyc();
300 extern void multi_send_wall_status (int,ubyte,ubyte,ubyte);
301 extern void multi_send_wall_status_specific (int,int,ubyte,ubyte,ubyte);
302
303 extern void game_disable_cheats();
304
305 char IWasKicked=0;
306 FILE *SendLogFile,*RecieveLogFile;
307 int TTSent[100],TTRecv[100];
308
309 extern int Final_boss_is_dead;
310
311 // following is network stuff for appletalk
312
313 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
314
315 #define NETWORK_OEM 0x10
316
317 #ifdef MACINTOSH
318
319 int Network_game_type;                                  // used to tell IPX vs. appletalk games
320
321 #define MAX_ZONES                       255
322 #define MAX_ZONE_LENGTH         33
323 #define DEFAULT_ZONE_NAME       "\p*"
324 #define MAX_REGISTER_TRIES      5                                       // maximum time we will try and register a netgame
325 char Network_zone_name[MAX_ZONE_LENGTH];                // zone name game being played in for appletalk
326 char Zone_names[MAX_ZONES][MAX_ZONE_LENGTH];    // total list of zones that we can see
327 ubyte appletalk_use_broadcast = 0;
328 ubyte Network_game_validated = 0;               // validates a game before being able to join
329 ubyte Network_game_validate_choice = 0;
330 ubyte Network_appletalk_type = 0;               // type of appletalk network game is being played on
331
332 #define ETHERTALK_TYPE  0
333 #define LOCALTALK_TYPE  1
334 #define OTHERTALK_TYPE  2
335
336
337 void network_release_registered_game(void);
338
339 #endif
340
341 void
342 network_init(void)
343 {
344   
345         // So you want to play a netgame, eh?  Let's a get a few things
346         // straight
347
348    int t;
349         int save_pnum = Player_num;
350
351         game_disable_cheats();
352    IWasKicked=0;
353    Final_boss_is_dead=0;
354    NamesInfoSecurity=-1;
355
356
357    #ifdef NETPROFILING
358            OpenSendLog();
359                 OpenRecieveLog(); 
360         #endif
361         
362         for (t=0;t<MAX_POWERUP_TYPES;t++)
363                 {
364                         MaxPowerupsAllowed[t]=0;
365                         PowerupsInMine[t]=0;
366                 }
367
368    TotalMissedPackets=0; TotalPacketsGot=0;
369
370         memset(&Netgame, 0, sizeof(netgame_info));
371         memset(&NetPlayers,0,sizeof(AllNetPlayers_info));
372         memset(&My_Seq, 0, sizeof(sequence_packet));
373         My_Seq.type = PID_REQUEST;
374         memcpy(My_Seq.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
375
376    #if defined (D2_OEM)
377            Version_minor|=NETWORK_OEM;
378         #endif
379  
380         My_Seq.player.version_major=Version_major;
381         My_Seq.player.version_minor=Version_minor;
382    My_Seq.player.rank=GetMyNetRanking();        
383  
384         if (Network_game_type == IPX_GAME) {
385                 memcpy(My_Seq.player.network.ipx.node, ipx_get_my_local_address(), 6);
386                 memcpy(My_Seq.player.network.ipx.server, ipx_get_my_server_address(), 4 );
387         #ifdef MACINTOSH
388         } else {
389                 My_Seq.player.network.appletalk.node = appletalk_get_my_node();
390                 My_Seq.player.network.appletalk.net = appletalk_get_my_net();
391                 My_Seq.player.network.appletalk.socket = appletalk_get_my_socket();
392         #endif
393         }
394 #ifdef MACINTOSH
395         My_Seq.player.computer_type = MAC;
396 #else
397         My_Seq.player.computer_type = DOS;
398 #endif
399
400         for (Player_num = 0; Player_num < MAX_NUM_NET_PLAYERS; Player_num++)
401                 init_player_stats_game();
402
403         Player_num = save_pnum;         
404         multi_new_game();
405         Network_new_game = 1;
406         Control_center_destroyed = 0;
407         network_flush();
408
409         Netgame.PacketsPerSec=10;
410
411    if ((t=FindArg("-packets")))
412     {
413      Netgame.PacketsPerSec=atoi(Args[t+1]);
414      if (Netgame.PacketsPerSec<1)
415       Netgame.PacketsPerSec=1;
416      else if (Netgame.PacketsPerSec>20)
417       Netgame.PacketsPerSec=20;
418      mprintf ((0,"Will send %d packets per second",Netgame.PacketsPerSec));
419     }
420    if (FindArg("-shortpackets"))
421     {
422      Netgame.ShortPackets=1;
423      mprintf ((0,"Will send short packets.\n"));
424     }
425 }
426
427 int
428 network_i_am_master(void)
429 {
430         // I am the lowest numbered player in this game?
431
432         int i;
433
434         if (!(Game_mode & GM_NETWORK))
435                 return (Player_num == 0);
436
437         for (i = 0; i < Player_num; i++)
438                 if (Players[i].connected)
439                         return 0;
440         return 1;
441 }
442 int
443 network_who_is_master(void)
444 {
445         // Who is the master of this game?
446
447         int i;
448
449         if (!(Game_mode & GM_NETWORK))
450                 return (Player_num == 0);
451
452         for (i = 0; i < N_players; i++)
453                 if (Players[i].connected)
454                         return i;
455         return Player_num;
456 }
457 int network_how_many_connected()
458  {
459   int num=0,i;
460  
461         for (i = 0; i < N_players; i++)
462                 if (Players[i].connected)
463                         num++;
464    return (num);
465  }
466
467 #define ENDLEVEL_SEND_INTERVAL (F1_0*2)
468 #define ENDLEVEL_IDLE_TIME      (F1_0*20)
469 /*      
470 void 
471 network_endlevel_poll( int nitems, newmenu_item * menus, int * key, int citem )
472 {
473         // Polling loop for End-of-level menu
474
475         static fix t1 = 0;
476         int i = 0;
477         int num_ready = 0;
478         int num_escaped = 0;
479         int goto_secret = 0;
480
481         int previous_state[MAX_NUM_NET_PLAYERS];
482         int previous_seconds_left;
483
484         menus = menus;
485         citem = citem;
486         nitems = nitems;
487         key = key;
488
489         // Send our endlevel packet at regular intervals
490
491         if (timer_get_approx_seconds() > (t1+ENDLEVEL_SEND_INTERVAL))
492         {
493                 network_send_endlevel_packet();
494                 t1 = timer_get_approx_seconds();
495         }
496
497         for (i = 0; i < N_players; i++)
498                 previous_state[i] = Players[i].connected;
499
500         previous_seconds_left = Countdown_seconds_left;
501
502         network_listen();
503
504         for (i = 0; i < N_players; i++)
505         {
506                 if (Players[i].connected == 1)
507                 {
508                         // Check timeout for idle players
509                         if (timer_get_approx_seconds() > LastPacketTime[i]+ENDLEVEL_IDLE_TIME)
510                         {
511                                 mprintf((0, "idle timeout for player %d.\n", i));
512                                 Players[i].connected = 0;
513                                 network_send_endlevel_sub(i);
514                         }                               
515                 }
516
517                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
518                         num_ready++;
519                 if (Players[i].connected != 1)
520                         num_escaped++;
521                 if (Players[i].connected == 4)
522                         goto_secret = 1;
523         }
524
525         if (num_escaped == N_players) // All players are out of the mine
526         {
527                 Countdown_seconds_left = -1;
528         }
529
530
531         if (num_ready == N_players) // All players have checked in or are disconnected
532         {
533                 if (goto_secret)
534                         *key = -3;
535                 else
536                         *key = -2;
537         }
538 } */
539   
540 void 
541 network_endlevel_poll2( int nitems, newmenu_item * menus, int * key, int citem )
542 {
543         // Polling loop for End-of-level menu
544
545         static fix t1 = 0;
546         int i = 0;
547         int num_ready = 0;
548         int goto_secret = 0;
549
550         menus = menus;
551         citem = citem;
552         nitems = nitems;
553         key = key;
554
555         // Send our endlevel packet at regular intervals
556
557         if (timer_get_approx_seconds() > (t1+ENDLEVEL_SEND_INTERVAL))
558         {
559                 network_send_endlevel_packet();
560                 t1 = timer_get_approx_seconds();
561         }
562
563 //   mprintf ((0,"Trying to listen!\n"));
564         network_listen();
565
566         for (i = 0; i < N_players; i++)
567         {
568                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
569                         num_ready++;
570                 if (Players[i].connected == 4)
571                         goto_secret = 1;                                        
572         }
573
574         if (num_ready == N_players) // All players have checked in or are disconnected
575         {
576                 if (goto_secret)
577                         *key = -3;
578                 else
579                         *key = -2;
580         }
581 }
582
583
584 extern fix StartAbortMenuTime;
585
586 void 
587 network_endlevel_poll3( int nitems, newmenu_item * menus, int * key, int citem )
588 {
589         // Polling loop for End-of-level menu
590
591    int num_ready=0,i;
592  
593         menus = menus;
594         citem = citem;
595         nitems = nitems;
596         key = key;
597
598         if (timer_get_approx_seconds() > (StartAbortMenuTime+(F1_0 * 8)))
599     *key=-2;
600
601
602         network_listen();
603
604
605         for (i = 0; i < N_players; i++)
606                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
607                         num_ready++;
608
609         if (num_ready == N_players) // All players have checked in or are disconnected
610                         *key = -2;
611
612 }
613
614
615 int
616 network_endlevel(int *secret)
617 {
618         // Do whatever needs to be done between levels
619
620    int i;
621
622    *secret=0;
623
624         //network_flush();
625
626         Network_status = NETSTAT_ENDLEVEL; // We are between levels
627
628         network_listen();
629
630         network_send_endlevel_packet();
631
632         for (i=0; i<N_players; i++) 
633         {
634                 LastPacketTime[i] = timer_get_approx_seconds();
635         }
636    
637         network_send_endlevel_packet();
638         network_send_endlevel_packet();
639         MySyncPackInitialized = 0;
640
641         network_update_netgame();
642
643         return(0);
644 }
645
646 int 
647 can_join_netgame(netgame_info *game,AllNetPlayers_info *people)
648 {
649         // Can this player rejoin a netgame in progress?
650
651         int i, num_players;
652
653         if (game->game_status == NETSTAT_STARTING)
654      return 1;
655
656         if (game->game_status != NETSTAT_PLAYING)
657     {
658       mprintf ((0,"Error: Can't join because game_status !=NETSTAT_PLAYING\n"));
659                 return 0;
660     }
661
662    if (game->version_major==0 && Version_major>0)
663     {
664            mprintf ((0,"Error:Can't join because version majors don't match!\n"));
665                 return (0);
666     }
667
668         if (game->version_major>0 && Version_major==0)
669     {
670            mprintf ((0,"Error:Can't join because version majors2 don't match!\n"));
671                 return (0);
672     }
673
674         // Game is in progress, figure out if this guy can re-join it
675
676         num_players = game->numplayers;
677
678         if (!(game->game_flags & NETGAME_FLAG_CLOSED)) {
679                 // Look for player that is not connected
680                 
681                 if (game->numconnected==game->max_numplayers)
682                  return (2);
683
684 //      mprintf ((0,"Refuse = %d\n",game->RefusePlayers));
685                 
686                 if (game->RefusePlayers)
687                  return (3);
688                 
689                 if (game->numplayers < game->max_numplayers)
690                         return 1;
691
692                 if (game->numconnected<num_players)
693                         return 1;
694                      
695         }
696
697         if (people==NULL)
698     {
699       mprintf ((0,"Error! Can't join because people==NULL!\n"));
700                 return 0;
701     }
702         
703         // Search to see if we were already in this closed netgame in progress
704
705         for (i = 0; i < num_players; i++) {
706                 if (Network_game_type == IPX_GAME) {
707                         if ( (!stricmp(Players[Player_num].callsign, people->players[i].callsign)) &&
708                                   (!memcmp(My_Seq.player.network.ipx.node, people->players[i].network.ipx.node, 6)) &&
709                                   (!memcmp(My_Seq.player.network.ipx.server, people->players[i].network.ipx.server, 4)) )
710                                 break;
711                 } else {
712                         if ( (!stricmp(Players[Player_num].callsign, people->players[i].callsign)) &&
713                                   (My_Seq.player.network.appletalk.node == people->players[i].network.appletalk.node) &&
714                                   (My_Seq.player.network.appletalk.net == people->players[i].network.appletalk.net) )
715                                 break;
716                 }
717         }
718
719         if (i != num_players)
720                 return 1;
721  
722    mprintf ((0,"Error: Can't join because at end of list!\n"));
723         return 0;
724 }
725
726 void
727 network_disconnect_player(int playernum)
728 {
729         // A player has disconnected from the net game, take whatever steps are
730         // necessary 
731
732         if (playernum == Player_num) 
733         {
734                 Int3(); // Weird, see Rob
735                 return;
736         }
737
738         Players[playernum].connected = 0;
739    NetPlayers.players[playernum].connected = 0;
740    if (VerifyPlayerJoined==playernum)
741           VerifyPlayerJoined=-1;
742
743 //      create_player_appearance_effect(&Objects[Players[playernum].objnum]);
744         multi_make_player_ghost(playernum);
745
746         if (Newdemo_state == ND_STATE_RECORDING)
747                 newdemo_record_multi_disconnect(playernum);
748
749         multi_strip_robots(playernum);
750 }
751                 
752 void
753 network_new_player(sequence_packet *their)
754 {
755         int objnum;
756         int pnum;
757
758         pnum = their->player.connected;
759
760         Assert(pnum >= 0);
761         Assert(pnum < MaxNumNetPlayers);        
762         
763         objnum = Players[pnum].objnum;
764
765         if (Newdemo_state == ND_STATE_RECORDING) {
766                 int new_player;
767
768                 if (pnum == N_players)
769                         new_player = 1;
770                 else
771                         new_player = 0;
772                 newdemo_record_multi_connect(pnum, new_player, their->player.callsign);
773         }
774
775         memcpy(Players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
776         memcpy(NetPlayers.players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
777         
778
779    ClipRank (&their->player.rank);
780    NetPlayers.players[pnum].rank=their->player.rank;
781         NetPlayers.players[pnum].version_major=their->player.version_major;
782         NetPlayers.players[pnum].version_minor=their->player.version_minor;
783    network_check_for_old_version(pnum);
784
785         if (Network_game_type == IPX_GAME) {
786                 if ( (*(uint *)their->player.network.ipx.server) != 0 )
787                         ipx_get_local_target( their->player.network.ipx.server, their->player.network.ipx.node, Players[pnum].net_address );
788                 else
789                         memcpy(Players[pnum].net_address, their->player.network.ipx.node, 6);
790         
791                 memcpy(NetPlayers.players[pnum].network.ipx.node, their->player.network.ipx.node, 6);
792                 memcpy(NetPlayers.players[pnum].network.ipx.server, their->player.network.ipx.server, 4);
793         } else {
794                 NetPlayers.players[pnum].network.appletalk.node = their->player.network.appletalk.node;
795                 NetPlayers.players[pnum].network.appletalk.net = their->player.network.appletalk.net;
796                 NetPlayers.players[pnum].network.appletalk.socket = their->player.network.appletalk.socket;
797         }
798
799         Players[pnum].n_packets_got = 0;
800         Players[pnum].connected = 1;
801         Players[pnum].net_kills_total = 0;
802         Players[pnum].net_killed_total = 0;
803         memset(kill_matrix[pnum], 0, MAX_PLAYERS*sizeof(short)); 
804         Players[pnum].score = 0;
805         Players[pnum].flags = 0;
806         Players[pnum].KillGoalCount=0;
807
808         if (pnum == N_players)
809         {
810                 N_players++;
811                 Netgame.numplayers = N_players;
812         }
813
814         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
815
816    ClipRank (&their->player.rank);
817    
818    if (FindArg("-norankings"))
819           HUD_init_message("'%s' %s\n",their->player.callsign, TXT_JOINING);
820    else   
821      HUD_init_message("%s'%s' %s\n",RankStrings[their->player.rank],their->player.callsign, TXT_JOINING);
822         
823         multi_make_ghost_player(pnum);
824
825         multi_send_score();
826         multi_sort_kill_list();
827
828 //      create_player_appearance_effect(&Objects[objnum]);
829 }
830
831 char RefuseThisPlayer=0,WaitForRefuseAnswer=0,RefuseTeam;
832 char RefusePlayerName[12];
833 fix RefuseTimeLimit=0;
834
835 void network_welcome_player(sequence_packet *their)
836 {
837         // Add a player to a game already in progress
838         ubyte local_address[6];
839         int player_num;
840         int i;
841
842    WaitForRefuseAnswer=0;
843
844         if (FindArg("-NoMatrixCheat"))
845         {
846                 if (their->player.version_minor & (0x0F<3))
847                 {
848                                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_DORK);
849                                         return;
850                 }
851         }
852
853         if (HoardEquipped())
854         {
855    // If hoard game, and this guy isn't D2 Christmas (v1.2), dump him
856
857            if ((Game_mode & GM_HOARD) && ((their->player.version_minor & 0x0F)<2))
858                 {
859                         if (Network_game_type == IPX_GAME)
860                                 network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_DORK);
861                         #ifdef MACINTOSH
862                         else
863                                 network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_DORK);
864                         #endif
865                         return;
866                 }
867         }
868
869         // Don't accept new players if we're ending this level.  Its safe to
870         // ignore since they'll request again later
871
872         if ((Endlevel_sequence) || (Control_center_destroyed))
873         {
874                 mprintf((0, "Ignored request from new player to join during endgame.\n"));
875                 if (Network_game_type == IPX_GAME)
876                         network_dump_player(their->player.network.ipx.server,their->player.network.ipx.node, DUMP_ENDLEVEL);
877                 #ifdef MACINTOSH
878                 else
879                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_ENDLEVEL);
880                 #endif
881                 return; 
882         }
883
884         if (Network_send_objects || Network_sending_extras)
885         {
886                 // Ignore silently, we're already responding to someone and we can't
887                 // do more than one person at a time.  If we don't dump them they will
888                 // re-request in a few seconds.
889                 return;
890         }
891
892         if (their->player.connected != Current_level_num)
893         {
894                 mprintf((0, "Dumping player due to old level number.\n"));
895                 if (Network_game_type == IPX_GAME)
896                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_LEVEL);
897                 #ifdef MACINTOSH
898                 else
899                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_LEVEL);
900                 #endif
901                 return;
902         }
903
904         player_num = -1;
905         memset(&Network_player_rejoining, 0, sizeof(sequence_packet));
906         Network_player_added = 0;
907
908         if (Network_game_type == IPX_GAME) {
909                 if ( (*(uint *)their->player.network.ipx.server) != 0 )
910                         ipx_get_local_target( their->player.network.ipx.server, their->player.network.ipx.node, local_address );
911                 else
912                         memcpy(local_address, their->player.network.ipx.node, 6);
913         }
914
915         for (i = 0; i < N_players; i++)
916         {
917                 if ( (Network_game_type == IPX_GAME) && (!stricmp(Players[i].callsign, their->player.callsign )) && (!memcmp(Players[i].net_address,local_address, 6)) ) 
918                 {
919                         player_num = i;
920                         break;
921                 }
922 #ifdef MACINTOSH                // note link to above if
923                         else if ( (!stricmp(Players[i].callsign, their->player.callsign)) &&
924                                     (NetPlayers.players[i].network.appletalk.node == their->player.network.appletalk.node) &&
925                                         (NetPlayers.players[i].network.appletalk.net == their->player.network.appletalk.net)) {
926                         player_num = i;
927                         break;
928                 }
929 #endif
930         }
931
932         if (player_num == -1)
933         {
934                 // Player is new to this game
935
936                 if ( !(Netgame.game_flags & NETGAME_FLAG_CLOSED) && (N_players < MaxNumNetPlayers))
937                 {
938                         // Add player in an open slot, game not full yet
939
940                         player_num = N_players;
941                         Network_player_added = 1;
942                 }
943                 else if (Netgame.game_flags & NETGAME_FLAG_CLOSED)
944                 {
945                         // Slots are open but game is closed
946
947                         if (Network_game_type == IPX_GAME)
948                                 network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_CLOSED);
949                         #ifdef MACINTOSH
950                         else
951                                 network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_CLOSED);
952                         #endif
953                         return;
954                 }
955                 else
956                 {
957                         // Slots are full but game is open, see if anyone is
958                         // disconnected and replace the oldest player with this new one
959                 
960                         int oldest_player = -1;
961                         fix oldest_time = timer_get_approx_seconds();
962
963                         Assert(N_players == MaxNumNetPlayers);
964
965                         for (i = 0; i < N_players; i++)
966                         {
967                                 if ( (!Players[i].connected) && (LastPacketTime[i] < oldest_time))
968                                 {
969                                         oldest_time = LastPacketTime[i];
970                                         oldest_player = i;
971                                 }
972                         }
973
974                         if (oldest_player == -1)
975                         {
976                                 // Everyone is still connected 
977
978                                 if (Network_game_type == IPX_GAME)
979                                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_FULL);
980                                 #ifdef MACINTOSH
981                                 else
982                                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_FULL);
983                                 #endif
984                                 return;
985                         }
986                         else
987                         {       
988                                 // Found a slot!
989
990                                 player_num = oldest_player;
991                                 Network_player_added = 1;
992                         }
993                 }
994         }
995         else 
996         {
997                 // Player is reconnecting
998                 
999                 if (Players[player_num].connected)
1000                 {
1001                         mprintf((0, "Extra REQUEST from player ignored.\n"));
1002                         return;
1003                 }
1004
1005                 if (Newdemo_state == ND_STATE_RECORDING)
1006                         newdemo_record_multi_reconnect(player_num);
1007
1008                 Network_player_added = 0;
1009
1010                 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1011                 
1012                 if (FindArg("-norankings"))
1013                         HUD_init_message("'%s' %s", Players[player_num].callsign, TXT_REJOIN);
1014                 else
1015                         HUD_init_message("%s'%s' %s", RankStrings[NetPlayers.players[player_num].rank],Players[player_num].callsign, TXT_REJOIN);
1016         }
1017
1018         Players[player_num].KillGoalCount=0;
1019
1020         // Send updated Objects data to the new/returning player
1021
1022         
1023         Network_player_rejoining = *their;
1024         Network_player_rejoining.player.connected = player_num;
1025         Network_send_objects = 1;
1026         Network_send_objnum = -1;
1027
1028         network_send_objects();
1029 }
1030
1031 int network_objnum_is_past(int objnum)
1032 {
1033         // determine whether or not a given object number has already been sent
1034         // to a re-joining player.
1035         
1036         int player_num = Network_player_rejoining.player.connected;
1037         int obj_mode = !((object_owner[objnum] == -1) || (object_owner[objnum] == player_num));
1038
1039         if (!Network_send_objects)
1040                 return 0; // We're not sending objects to a new player
1041
1042         if (obj_mode > Network_send_object_mode)
1043                 return 0;
1044         else if (obj_mode < Network_send_object_mode)
1045                 return 1;
1046         else if (objnum < Network_send_objnum)
1047                 return 1;
1048         else
1049                 return 0;
1050 }
1051
1052 #define OBJ_PACKETS_PER_FRAME 1
1053 extern void multi_send_active_door(char);
1054 extern void multi_send_door_open_specific(int,int,int,ubyte);
1055
1056
1057 void network_send_door_updates(int pnum)
1058 {
1059         // Send door status when new player joins
1060         
1061         int i;
1062    
1063    pnum=pnum;
1064
1065 //   Assert (pnum>-1 && pnum<N_players);
1066
1067         for (i = 0; i < Num_walls; i++)
1068         {
1069       if ((Walls[i].type == WALL_DOOR) && ((Walls[i].state == WALL_DOOR_OPENING) || (Walls[i].state == WALL_DOOR_WAITING) || (Walls[i].state == WALL_DOOR_OPEN)))
1070                         multi_send_door_open_specific(pnum,Walls[i].segnum, Walls[i].sidenum,Walls[i].flags);
1071                 else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].flags & WALL_BLASTED))
1072                         multi_send_door_open_specific(pnum,Walls[i].segnum, Walls[i].sidenum,Walls[i].flags);
1073                 else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].hps != WALL_HPS))
1074                         multi_send_hostage_door_status(i);
1075                 else
1076                         multi_send_wall_status_specific(pnum,i,Walls[i].type,Walls[i].flags,Walls[i].state);
1077         }
1078 }
1079
1080 extern vms_vector MarkerPoint[];
1081 void network_send_markers()
1082  {
1083   // send marker positions/text to new player
1084
1085   
1086   int i;
1087   
1088   for (i=0;i<8;i++)
1089    {
1090     if (MarkerObject[(i*2)]!=-1)
1091      multi_send_drop_marker (i,MarkerPoint[(i*2)],0,MarkerMessage[i*2]);
1092     if (MarkerObject[(i*2)+1]!=-1)
1093      multi_send_drop_marker (i,MarkerPoint[(i*2)+1],1,MarkerMessage[(i*2)+1]);
1094    }
1095  }
1096
1097 void network_process_monitor_vector(int vector)
1098 {
1099         int i, j;
1100         int count = 0;
1101         segment *seg;
1102         
1103         for (i=0; i <= Highest_segment_index; i++)
1104         {
1105                 int tm, ec, bm;
1106                 seg = &Segments[i];
1107                 for (j = 0; j < 6; j++)
1108                 {
1109                         if ( ((tm = seg->sides[j].tmap_num2) != 0) &&
1110                                   ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
1111                                   ((bm = Effects[ec].dest_bm_num) != -1) )
1112                         {
1113                                 if (vector & (1 << count))
1114                                 {
1115                                         seg->sides[j].tmap_num2 = bm | (tm&0xc000);
1116                                 //      mprintf((0, "Monitor %d blown up.\n", count));
1117                                 }
1118                                 //else
1119                                   //    mprintf((0, "Monitor %d intact.\n", count));
1120                                 count++;
1121                                 Assert(count < 32);
1122                         }
1123                 }
1124         }
1125 }
1126
1127 int network_create_monitor_vector(void)
1128 {
1129         int i, j, k;
1130         int num_blown_bitmaps = 0;
1131         int monitor_num = 0;
1132         #define NUM_BLOWN_BITMAPS 20
1133         int blown_bitmaps[NUM_BLOWN_BITMAPS];
1134         int vector = 0;
1135         segment *seg;
1136
1137         for (i=0; i < Num_effects; i++)
1138         {
1139                 if (Effects[i].dest_bm_num > 0) {
1140                         for (j = 0; j < num_blown_bitmaps; j++)
1141                                 if (blown_bitmaps[j] == Effects[i].dest_bm_num)
1142                                         break;
1143                         if (j == num_blown_bitmaps) {
1144                                 blown_bitmaps[num_blown_bitmaps++] = Effects[i].dest_bm_num;
1145                                 Assert(num_blown_bitmaps < NUM_BLOWN_BITMAPS);
1146                         }
1147                 }
1148         }               
1149                 
1150 //      for (i = 0; i < num_blown_bitmaps; i++)
1151 //              mprintf((0, "Blown bitmap #%d = %d.\n", i, blown_bitmaps[i]));
1152
1153         for (i=0; i <= Highest_segment_index; i++)
1154         {
1155                 int tm, ec;
1156                 seg = &Segments[i];
1157                 for (j = 0; j < 6; j++)
1158                 {
1159                         if ((tm = seg->sides[j].tmap_num2) != 0) 
1160                         {
1161                                 if ( ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
1162                                           (Effects[ec].dest_bm_num != -1) )
1163                                 {
1164                                 //      mprintf((0, "Monitor %d intact.\n", monitor_num));
1165                                         monitor_num++;
1166                                         Assert(monitor_num < 32);
1167                                 }
1168                                 else
1169                                 {
1170                                         for (k = 0; k < num_blown_bitmaps; k++)
1171                                         {
1172                                                 if ((tm&0x3fff) == blown_bitmaps[k])
1173                                                 {
1174                                                         //mprintf((0, "Monitor %d destroyed.\n", monitor_num));
1175                                                         vector |= (1 << monitor_num);
1176                                                         monitor_num++;
1177                                                         Assert(monitor_num < 32);
1178                                                         break;
1179                                                 }
1180                                         }
1181                                 }
1182                         }
1183                 }
1184         }
1185   //    mprintf((0, "Final monitor vector %x.\n", vector));
1186         return(vector);
1187 }
1188
1189 void network_stop_resync(sequence_packet *their)
1190 {
1191         if (Network_game_type == IPX_GAME) {
1192                 if ( (!memcmp(Network_player_rejoining.player.network.ipx.node, their->player.network.ipx.node, 6)) &&
1193                           (!memcmp(Network_player_rejoining.player.network.ipx.server, their->player.network.ipx.server, 4)) &&
1194                      (!stricmp(Network_player_rejoining.player.callsign, their->player.callsign)) )
1195                 {
1196                         mprintf((0, "Aborting resync for player %s.\n", their->player.callsign));
1197                         Network_send_objects = 0;
1198                         Network_sending_extras=0;
1199                         Network_rejoined=0;
1200                         Player_joining_extras=-1;
1201                         Network_send_objnum = -1;
1202                 }
1203         } else {
1204                 if ( (Network_player_rejoining.player.network.appletalk.node == their->player.network.appletalk.node) &&
1205                          (Network_player_rejoining.player.network.appletalk.net == their->player.network.appletalk.net) &&
1206                          (!stricmp(Network_player_rejoining.player.callsign, their->player.callsign)) )
1207                 {
1208                         mprintf((0, "Aborting resync for player %s.\n", their->player.callsign));
1209                         Network_send_objects = 0;
1210                         Network_sending_extras=0;
1211                         Network_rejoined=0;
1212                         Player_joining_extras=-1;
1213                         Network_send_objnum = -1;
1214                 }
1215         }
1216 }
1217
1218 byte object_buffer[IPX_MAX_DATA_SIZE];
1219
1220 void network_send_objects(void)
1221 {
1222         short remote_objnum;
1223         byte owner;
1224         int loc, i, h;
1225
1226         static int obj_count = 0;
1227         static int frame_num = 0;
1228
1229         int obj_count_frame = 0;
1230         int player_num = Network_player_rejoining.player.connected;
1231
1232         // Send clear objects array trigger and send player num
1233
1234         Assert(Network_send_objects != 0);
1235         Assert(player_num >= 0);
1236         Assert(player_num < MaxNumNetPlayers);
1237
1238         if (Endlevel_sequence || Control_center_destroyed)
1239         {
1240                 // Endlevel started before we finished sending the goods, we'll
1241                 // have to stop and try again after the level.
1242
1243                 if (Network_game_type == IPX_GAME)
1244                         network_dump_player(Network_player_rejoining.player.network.ipx.server,Network_player_rejoining.player.network.ipx.node, DUMP_ENDLEVEL);
1245                 #ifdef MACINTOSH
1246                 else
1247                         network_dump_appletalk_player(Network_player_rejoining.player.network.appletalk.node,Network_player_rejoining.player.network.appletalk.net, Network_player_rejoining.player.network.appletalk.socket, DUMP_ENDLEVEL);
1248                 #endif
1249                 Network_send_objects = 0; 
1250                 return;
1251         }
1252
1253         for (h = 0; h < OBJ_PACKETS_PER_FRAME; h++) // Do more than 1 per frame, try to speed it up without
1254                                                                                                                           // over-stressing the receiver.
1255         {
1256                 obj_count_frame = 0;
1257                 memset(object_buffer, 0, IPX_MAX_DATA_SIZE);
1258                 object_buffer[0] = PID_OBJECT_DATA;
1259                 loc = 3;
1260         
1261                 if (Network_send_objnum == -1)
1262                 {
1263                         obj_count = 0;
1264                         Network_send_object_mode = 0;
1265 //       mprintf((0, "Sending object array to player %d.\n", player_num));
1266                         *(short *)(object_buffer+loc) = INTEL_SHORT(-1);        loc += 2;
1267                         object_buffer[loc] = player_num;                loc += 1;
1268                                                                                                         loc += 2; // Placeholder for remote_objnum, not used here
1269                         Network_send_objnum = 0;
1270                         obj_count_frame = 1;
1271                         frame_num = 0;
1272                 }
1273                 
1274                 for (i = Network_send_objnum; i <= Highest_object_index; i++)
1275                 {
1276                         if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) &&
1277                                  (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) &&
1278                                  (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE) &&
1279                                  !(Objects[i].type==OBJ_WEAPON && Objects[i].id==PMINE_ID))
1280                                 continue;
1281                         if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num)))
1282                                 continue;
1283                         if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num)))
1284                                 continue;
1285
1286                         if ( ((IPX_MAX_DATA_SIZE-1) - loc) < (sizeof(object)+5) )
1287                                 break; // Not enough room for another object
1288
1289                         obj_count_frame++;
1290                         obj_count++;
1291         
1292                         remote_objnum = objnum_local_to_remote((short)i, &owner);
1293                         Assert(owner == object_owner[i]);
1294
1295                         *(short *)(object_buffer+loc) = INTEL_SHORT((short)i);                          loc += 2;
1296                         object_buffer[loc] = owner;                                                                                     loc += 1;
1297                         *(short *)(object_buffer+loc) = INTEL_SHORT(remote_objnum);             loc += 2;
1298 #ifndef MACINTOSH
1299                         memcpy(object_buffer+loc, &Objects[i], sizeof(object)); loc += sizeof(object);
1300 #else
1301                         if (Network_game_type == IPX_GAME) {
1302                                 object tmpobj;
1303
1304                                 memcpy(&tmpobj, &(Objects[i]), sizeof(object));
1305                                 swap_object(&tmpobj);
1306                                 memcpy(&(object_buffer[loc]), &tmpobj, sizeof(object));                 loc += sizeof(object);
1307                         }
1308                         else
1309                                 memcpy(object_buffer+loc, &Objects[i], sizeof(object)); loc += sizeof(object);
1310 #endif
1311 //                      mprintf((0, "..packing object %d, remote %d\n", i, remote_objnum));
1312                 }
1313
1314                 if (obj_count_frame) // Send any objects we've buffered
1315                 {
1316                         frame_num++;
1317         
1318                         Network_send_objnum = i;
1319                         object_buffer[1] = obj_count_frame;  object_buffer[2] = frame_num;
1320 //       mprintf((0, "Object packet %d contains %d objects.\n", frame_num, obj_count_frame));
1321
1322                         Assert(loc <= IPX_MAX_DATA_SIZE);
1323
1324                         if (Network_game_type == IPX_GAME)
1325                                 ipx_send_internetwork_packet_data( object_buffer, loc, Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1326                         #ifdef MACINTOSH
1327                         else
1328                                 appletalk_send_packet_data( object_buffer, loc, Network_player_rejoining.player.network.appletalk.node,
1329                                         Network_player_rejoining.player.network.appletalk.net,
1330                                         Network_player_rejoining.player.network.appletalk.socket);
1331                         #endif
1332
1333                         // OLD ipx_send_packet_data(object_buffer, loc, &Network_player_rejoining.player.node);
1334                 }
1335
1336                 if (i > Highest_object_index)
1337                 {
1338                         if (Network_send_object_mode == 0)
1339                         {
1340                                 Network_send_objnum = 0;
1341                                 Network_send_object_mode = 1; // go to next mode
1342                         }
1343                         else 
1344                         {
1345                                 Assert(Network_send_object_mode == 1); 
1346
1347                                 frame_num++;
1348                                 // Send count so other side can make sure he got them all
1349 //                              mprintf((0, "Sending end marker in packet #%d.\n", frame_num));
1350                                 mprintf((0, "Sent %d objects.\n", obj_count));
1351                                 object_buffer[0] = PID_OBJECT_DATA;
1352                                 object_buffer[1] = 1;
1353                                 object_buffer[2] = frame_num;
1354                                 *(short *)(object_buffer+3) = INTEL_SHORT(-2);
1355                                 *(short *)(object_buffer+6) = INTEL_SHORT(obj_count);
1356                                 //OLD ipx_send_packet_data(object_buffer, 8, &Network_player_rejoining.player.node);
1357                                 if (Network_game_type == IPX_GAME)
1358                                         ipx_send_internetwork_packet_data(object_buffer, 8, Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node);
1359                                 #ifdef MACINTOSH
1360                                 else
1361                                         appletalk_send_packet_data( object_buffer, 8, Network_player_rejoining.player.network.appletalk.node,
1362                                                                                                 Network_player_rejoining.player.network.appletalk.net,
1363                                                                                                 Network_player_rejoining.player.network.appletalk.socket);
1364                                 #endif
1365                                 
1366                         
1367                                 // Send sync packet which tells the player who he is and to start!
1368                                 network_send_rejoin_sync(player_num);
1369                                 mprintf ((0,"VerfiyPlayerJoined is now set to %d\n",player_num));
1370                                 VerifyPlayerJoined=player_num;
1371
1372                                 // Turn off send object mode
1373                                 Network_send_objnum = -1;
1374                                 Network_send_objects = 0;
1375                                 obj_count = 0;
1376
1377                                 //if (!network_i_am_master ())
1378                                 // Int3();  // Bad!! Get Jason.  Someone goofy is trying to get ahold of the game!
1379
1380                                 Network_sending_extras=40; // start to send extras
1381                            Player_joining_extras=player_num;
1382
1383                                 return;
1384                         } // mode == 1;
1385                 } // i > Highest_object_index
1386         } // For PACKETS_PER_FRAME
1387 }
1388
1389 extern void multi_send_powerup_update();
1390
1391 void network_send_rejoin_sync(int player_num)
1392 {
1393         int i, j;
1394
1395         Players[player_num].connected = 1; // connect the new guy
1396         LastPacketTime[player_num] = timer_get_approx_seconds();
1397
1398         if (Endlevel_sequence || Control_center_destroyed)
1399         {
1400                 // Endlevel started before we finished sending the goods, we'll
1401                 // have to stop and try again after the level.
1402
1403                 if (Network_game_type == IPX_GAME)
1404                         network_dump_player(Network_player_rejoining.player.network.ipx.server,Network_player_rejoining.player.network.ipx.node, DUMP_ENDLEVEL);
1405                 #ifdef MACINTOSH
1406                 else
1407                         network_dump_appletalk_player(Network_player_rejoining.player.network.appletalk.node,Network_player_rejoining.player.network.appletalk.net, Network_player_rejoining.player.network.appletalk.socket, DUMP_ENDLEVEL);
1408                 #endif
1409                 Network_send_objects = 0; 
1410                 Network_sending_extras=0;
1411                 return;
1412         }
1413
1414         if (Network_player_added)
1415         {
1416                 Network_player_rejoining.type = PID_ADDPLAYER;
1417                 Network_player_rejoining.player.connected = player_num;
1418                 network_new_player(&Network_player_rejoining);
1419
1420                 for (i = 0; i < N_players; i++)
1421                 {
1422                         if ((i != player_num) && (i != Player_num) && (Players[i].connected))
1423                                 if (Network_game_type == IPX_GAME) {
1424                                         #ifndef MACINTOSH
1425                                         ipx_send_packet_data( (ubyte *)&Network_player_rejoining, sizeof(sequence_packet), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, Players[i].net_address);
1426                                         #else
1427                                         send_sequence_packet( Network_player_rejoining, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, Players[i].net_address);
1428                                         #endif
1429                                 #ifdef MACINTOSH
1430                                 } else {
1431                                         appletalk_send_packet_data( (ubyte *)&Network_player_rejoining, sizeof(sequence_packet), NetPlayers.players[i].network.appletalk.node,
1432                                                                                                 NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket);
1433                                 #endif
1434                                 }
1435                 }
1436         }       
1437
1438         // Send sync packet to the new guy
1439
1440         network_update_netgame();
1441
1442         // Fill in the kill list
1443         for (j=0; j<MAX_PLAYERS; j++)
1444         {
1445                 for (i=0; i<MAX_PLAYERS;i++)
1446                         Netgame.kills[j][i] = kill_matrix[j][i];
1447                 Netgame.killed[j] = Players[j].net_killed_total;
1448                 Netgame.player_kills[j] = Players[j].net_kills_total;
1449                 Netgame.player_score[j] = Players[j].score;
1450         }       
1451
1452         Netgame.level_time = Players[Player_num].time_level;
1453         Netgame.monitor_vector = network_create_monitor_vector();
1454
1455         mprintf((0, "Sending rejoin sync packet!!!\n"));
1456
1457         if (Network_game_type == IPX_GAME) {
1458                 #ifndef MACINTOSH       
1459                 ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1460                 ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1461                 #else
1462                 send_netgame_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node, NULL, 0);
1463                 send_netplayers_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node);
1464                 #endif
1465         #ifdef MACINTOSH
1466         } else {
1467                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.appletalk.node,
1468                                                                         Network_player_rejoining.player.network.appletalk.net,
1469                                                                         Network_player_rejoining.player.network.appletalk.socket);
1470                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.appletalk.node,
1471                                                                         Network_player_rejoining.player.network.appletalk.net,
1472                                                                         Network_player_rejoining.player.network.appletalk.socket);
1473         #endif
1474         }
1475         return;
1476 }
1477 void resend_sync_due_to_packet_loss_for_allender ()
1478 {
1479    int i,j;
1480
1481    mprintf ((0,"I'm resending a sync packet! VPJ=%d\n",VerifyPlayerJoined));
1482   
1483         network_update_netgame();
1484
1485         // Fill in the kill list
1486         for (j=0; j<MAX_PLAYERS; j++)
1487         {
1488                 for (i=0; i<MAX_PLAYERS;i++)
1489                         Netgame.kills[j][i] = kill_matrix[j][i];
1490                 Netgame.killed[j] = Players[j].net_killed_total;
1491                 Netgame.player_kills[j] = Players[j].net_kills_total;
1492                 Netgame.player_score[j] = Players[j].score;
1493         }       
1494
1495         Netgame.level_time = Players[Player_num].time_level;
1496         Netgame.monitor_vector = network_create_monitor_vector();
1497
1498         if (Network_game_type == IPX_GAME) {
1499                 #ifndef MACINTOSH       
1500                 ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1501                 ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1502                 #else
1503                 send_netgame_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node, NULL, 0);
1504                 send_netplayers_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node);
1505                 #endif
1506         #ifdef MACINTOSH
1507         } else {
1508                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.appletalk.node,
1509                                                                         Network_player_rejoining.player.network.appletalk.net,
1510                                                                         Network_player_rejoining.player.network.appletalk.socket);
1511                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.appletalk.node,
1512                                                                         Network_player_rejoining.player.network.appletalk.net,
1513                                                                         Network_player_rejoining.player.network.appletalk.socket);
1514         #endif
1515         }
1516 }
1517
1518
1519 char * network_get_player_name( int objnum )
1520 {
1521         if ( objnum < 0 ) return NULL; 
1522         if ( Objects[objnum].type != OBJ_PLAYER ) return NULL;
1523         if ( Objects[objnum].id >= MAX_PLAYERS ) return NULL;
1524         if ( Objects[objnum].id >= N_players ) return NULL;
1525         
1526         return Players[Objects[objnum].id].callsign;
1527 }
1528
1529
1530 void network_add_player(sequence_packet *p)
1531 {
1532         int i;
1533         
1534         mprintf((0, "Got add player request!\n"));
1535
1536         for (i=0; i<N_players; i++ )    {
1537                 if (Network_game_type == IPX_GAME) {
1538                         if ( !memcmp( NetPlayers.players[i].network.ipx.node, p->player.network.ipx.node, 6) && !memcmp(NetPlayers.players[i].network.ipx.server, p->player.network.ipx.server, 4)) 
1539                                 return;         // already got them
1540                 } else {
1541                         if ( (NetPlayers.players[i].network.appletalk.node == p->player.network.appletalk.node) &&
1542                                  (NetPlayers.players[i].network.appletalk.net == p->player.network.appletalk.net))
1543                                         return;
1544                 }
1545         }
1546
1547         if (Network_game_type == IPX_GAME) {
1548                 memcpy( NetPlayers.players[N_players].network.ipx.node, p->player.network.ipx.node, 6 );
1549                 memcpy( NetPlayers.players[N_players].network.ipx.server, p->player.network.ipx.server, 4 );
1550         } else {
1551                 NetPlayers.players[N_players].network.appletalk.node = p->player.network.appletalk.node;
1552                 NetPlayers.players[N_players].network.appletalk.net = p->player.network.appletalk.net;
1553                 NetPlayers.players[N_players].network.appletalk.socket = p->player.network.appletalk.socket;
1554         }
1555    
1556    ClipRank (&p->player.rank);
1557   
1558         memcpy( NetPlayers.players[N_players].callsign, p->player.callsign, CALLSIGN_LEN+1 );
1559         NetPlayers.players[N_players].version_major=p->player.version_major;
1560         NetPlayers.players[N_players].version_minor=p->player.version_minor;
1561    NetPlayers.players[N_players].rank=p->player.rank;
1562         NetPlayers.players[N_players].connected = 1;
1563    network_check_for_old_version (N_players);
1564
1565         Players[N_players].KillGoalCount=0;
1566         Players[N_players].connected = 1;
1567         LastPacketTime[N_players] = timer_get_approx_seconds();
1568         N_players++;
1569         Netgame.numplayers = N_players;
1570
1571         // Broadcast updated info
1572
1573    mprintf ((0,"sending_game_info!\n"));
1574         network_send_game_info(NULL);
1575 }
1576
1577 // One of the players decided not to join the game
1578
1579 void network_remove_player(sequence_packet *p)
1580 {
1581         int i,pn;
1582         
1583         pn = -1;
1584         for (i=0; i<N_players; i++ )    {
1585                 if (Network_game_type == IPX_GAME) {
1586                         if (!memcmp(NetPlayers.players[i].network.ipx.node, p->player.network.ipx.node, 6) && !memcmp(NetPlayers.players[i].network.ipx.server, p->player.network.ipx.server, 4)) {
1587                                 pn = i;
1588                                 break;
1589                         }
1590                 } else {
1591                         if ( (NetPlayers.players[i].network.appletalk.node == p->player.network.appletalk.node) && (NetPlayers.players[i].network.appletalk.net == p->player.network.appletalk.net) ) {
1592                                 pn = i;
1593                                 break;
1594                         }
1595                 }
1596         }
1597         
1598         if (pn < 0 ) return;
1599
1600         for (i=pn; i<N_players-1; i++ ) {
1601                 if (Network_game_type == IPX_GAME) {
1602                         memcpy( NetPlayers.players[i].network.ipx.node, NetPlayers.players[i+1].network.ipx.node, 6 );
1603                         memcpy( NetPlayers.players[i].network.ipx.server, NetPlayers.players[i+1].network.ipx.server, 4 );
1604                 } else {
1605                         NetPlayers.players[i].network.appletalk.node = NetPlayers.players[i+1].network.appletalk.node;
1606                         NetPlayers.players[i].network.appletalk.net = NetPlayers.players[i+1].network.appletalk.net;
1607                         NetPlayers.players[i].network.appletalk.socket = NetPlayers.players[i+1].network.appletalk.socket;
1608                 }
1609                 memcpy( NetPlayers.players[i].callsign, NetPlayers.players[i+1].callsign, CALLSIGN_LEN+1 );
1610                 NetPlayers.players[i].version_major=NetPlayers.players[i+1].version_major;
1611                 NetPlayers.players[i].version_minor=NetPlayers.players[i+1].version_minor;
1612
1613            NetPlayers.players[i].rank=NetPlayers.players[i+1].rank;
1614                 ClipRank (&NetPlayers.players[i].rank);
1615            network_check_for_old_version(i);    
1616         }
1617                 
1618         N_players--;
1619         Netgame.numplayers = N_players;
1620
1621         // Broadcast new info
1622
1623         network_send_game_info(NULL);
1624
1625 }
1626
1627 void
1628 network_dump_player(ubyte * server, ubyte *node, int why)
1629 {
1630         // Inform player that he was not chosen for the netgame
1631
1632         sequence_packet temp;
1633
1634         temp.type = PID_DUMP;
1635         memcpy(temp.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
1636         temp.player.connected = why;
1637         if (Network_game_type == IPX_GAME) {
1638                 #ifndef MACINTOSH
1639                 ipx_send_internetwork_packet_data( (ubyte *)&temp, sizeof(sequence_packet), server, node);
1640                 #else
1641                 send_sequence_packet( temp, server, node, NULL);
1642                 #endif
1643         } else {
1644                 Int3();
1645         }
1646 }
1647
1648 #ifdef MACINTOSH
1649 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why)
1650 {
1651         sequence_packet temp;
1652
1653         temp.type = PID_DUMP;
1654         memcpy(temp.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
1655         temp.player.connected = why;
1656         if (Network_game_type == APPLETALK_GAME) {
1657                 appletalk_send_packet_data( (ubyte *)&temp, sizeof(sequence_packet), node, net, socket );
1658         } else {
1659                 Int3();
1660         }
1661 }
1662 #endif
1663
1664 void
1665 network_send_game_list_request()
1666 {
1667         // Send a broadcast request for game info
1668
1669         sequence_packet me;
1670
1671         mprintf((0, "Sending game_list request.\n"));
1672         me.type = PID_GAME_LIST;
1673         memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
1674
1675         if (Network_game_type == IPX_GAME) {
1676                 memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
1677                 memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
1678
1679                 #ifndef MACINTOSH       
1680                 ipx_send_broadcast_packet_data( (ubyte *)&me, sizeof(sequence_packet) );
1681                 #else
1682                 send_sequence_packet( me, NULL, NULL, NULL);
1683                 #endif
1684         #ifdef MACINTOSH
1685         } else {
1686                 me.player.network.appletalk.node = appletalk_get_my_node();
1687                 me.player.network.appletalk.net = appletalk_get_my_net();
1688                 me.player.network.appletalk.socket = appletalk_get_my_socket();
1689                 appletalk_send_game_info( (ubyte *)&me, sizeof(sequence_packet), Network_zone_name );
1690         #endif
1691         }
1692 }
1693
1694 void network_send_all_info_request(char type,int which_security)
1695 {
1696         // Send a broadcast request for game info
1697
1698         sequence_packet me;
1699
1700         mprintf((0, "Sending all_info request.\n"));
1701    
1702         me.Security=which_security;
1703         me.type = type;
1704         memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
1705         
1706         if (Network_game_type == IPX_GAME) {
1707                 memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
1708                 memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
1709
1710                 #ifndef MACINTOSH       
1711                 ipx_send_broadcast_packet_data( (ubyte *)&me, sizeof(sequence_packet) );
1712                 #else
1713                 send_sequence_packet(me, NULL, NULL, NULL);
1714                 #endif
1715         #ifdef MACINTOSH
1716         } else {
1717                 me.player.network.appletalk.node = appletalk_get_my_node();
1718                 me.player.network.appletalk.net = appletalk_get_my_net();
1719                 me.player.network.appletalk.socket = appletalk_get_my_socket();
1720                 appletalk_send_game_info( (ubyte *)&me, sizeof(sequence_packet), Network_zone_name );
1721         #endif
1722         }
1723 }
1724
1725
1726 void
1727 network_update_netgame(void)
1728 {
1729         // Update the netgame struct with current game variables
1730
1731         int i, j;
1732
1733    Netgame.numconnected=0;
1734    for (i=0;i<N_players;i++)
1735          if (Players[i].connected)
1736                 Netgame.numconnected++;
1737
1738 // This is great: D2 1.0 and 1.1 ignore upper part of the game_flags field of
1739 //      the lite_info struct when you're sitting on the join netgame screen.  We can
1740 //      "sneak" Hoard information into this field.  This is better than sending 
1741 //      another packet that could be lost in transit.
1742
1743
1744         if (HoardEquipped())
1745         {
1746                 if (Game_mode & GM_HOARD)
1747                 {
1748                         Netgame.game_flags |=NETGAME_FLAG_HOARD;
1749                         if (Game_mode & GM_TEAM)
1750                                 Netgame.game_flags |=NETGAME_FLAG_TEAM_HOARD;
1751                 }
1752         }
1753  
1754         if (Network_status == NETSTAT_STARTING)
1755                 return;
1756
1757         Netgame.numplayers = N_players;
1758         Netgame.game_status = Network_status;
1759         Netgame.max_numplayers = MaxNumNetPlayers;
1760
1761         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++) 
1762         {
1763                 NetPlayers.players[i].connected = Players[i].connected;
1764                 for(j = 0; j < MAX_NUM_NET_PLAYERS; j++)
1765                         Netgame.kills[i][j] = kill_matrix[i][j];
1766
1767                 Netgame.killed[i] = Players[i].net_killed_total;
1768                 Netgame.player_kills[i] = Players[i].net_kills_total;
1769                 Netgame.player_score[i] = Players[i].score;
1770                 Netgame.player_flags[i] = (Players[i].flags & (PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY));
1771         }
1772         Netgame.team_kills[0] = team_kills[0];
1773         Netgame.team_kills[1] = team_kills[1];
1774         Netgame.levelnum = Current_level_num;
1775
1776  
1777 }
1778
1779 void
1780 network_send_endlevel_sub(int player_num)
1781 {
1782         endlevel_info end;
1783         int i, j;
1784
1785         // Send an endlevel packet for a player
1786         end.type                = PID_ENDLEVEL;
1787         end.player_num = player_num;
1788         end.connected   = Players[player_num].connected;
1789         end.kills               = INTEL_SHORT(Players[player_num].net_kills_total);
1790         end.killed              = INTEL_SHORT(Players[player_num].net_killed_total);
1791         memcpy(end.kill_matrix, kill_matrix[player_num], MAX_PLAYERS*sizeof(short));
1792 #ifdef MACINTOSH
1793         for (i = 0; i < MAX_PLAYERS; i++)
1794                 for (j = 0; j < MAX_PLAYERS; j++)
1795                         end.kill_matrix[i][j] = INTEL_SHORT(end.kill_matrix[i][j]);
1796 #else
1797         j = j;          // to satisfy compiler
1798 #endif
1799
1800         if (Players[player_num].connected == 1) // Still playing
1801         {
1802                 Assert(Control_center_destroyed);
1803                 end.seconds_left = Countdown_seconds_left;
1804         }
1805
1806 //      mprintf((0, "Sending endlevel packet.\n"));
1807
1808         for (i = 0; i < N_players; i++)
1809         {       
1810                 if ((i != Player_num) && (i!=player_num) && (Players[i].connected)) {
1811                   if (Players[i].connected==1)
1812                          network_send_endlevel_short_sub(player_num,i);
1813                   else {
1814                         if (Network_game_type == IPX_GAME)
1815                                 ipx_send_packet_data((ubyte *)&end, sizeof(endlevel_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
1816                         #ifdef MACINTOSH
1817                         else
1818                                 appletalk_send_packet_data( (ubyte *)&end, sizeof(endlevel_info), NetPlayers.players[i].network.appletalk.node,
1819                                                                                         NetPlayers.players[i].network.appletalk.net,
1820                                                                                         NetPlayers.players[i].network.appletalk.socket);
1821                         #endif
1822                         }       
1823                 }
1824         }
1825 }
1826
1827 void
1828 network_send_endlevel_packet(void)
1829 {
1830         // Send an updated endlevel status to other hosts
1831
1832         network_send_endlevel_sub(Player_num);
1833 }
1834
1835
1836 void
1837 network_send_endlevel_short_sub(int from_player_num,int to_player)
1838 {
1839         endlevel_info_short end;
1840
1841         // Send an endlevel packet for a player
1842         end.type                = PID_ENDLEVEL_SHORT;
1843         end.player_num = from_player_num;
1844         end.connected   = Players[from_player_num].connected;
1845         end.seconds_left = Countdown_seconds_left;
1846
1847
1848         if (Players[from_player_num].connected == 1) // Still playing
1849         {
1850                 Assert(Control_center_destroyed);
1851         }
1852
1853         if ((to_player != Player_num) && (to_player!=from_player_num) && (Players[to_player].connected))
1854         {
1855                 mprintf((0, "Sending short endlevel packet to %s.\n",Players[to_player].callsign));
1856                 if (Network_game_type == IPX_GAME)
1857                         ipx_send_packet_data((ubyte *)&end, sizeof(endlevel_info_short), NetPlayers.players[to_player].network.ipx.server, NetPlayers.players[to_player].network.ipx.node,Players[to_player].net_address);
1858                 #ifdef MACINTOSH
1859                 else
1860                         appletalk_send_packet_data( (ubyte *)&end, sizeof(endlevel_info_short), NetPlayers.players[to_player].network.appletalk.node,
1861                                                                                 NetPlayers.players[to_player].network.appletalk.net,
1862                                                                                 NetPlayers.players[to_player].network.appletalk.socket);
1863                 #endif
1864         }
1865 }
1866
1867 extern fix ThisLevelTime;
1868
1869 void
1870 network_send_game_info(sequence_packet *their)
1871 {
1872         // Send game info to someone who requested it
1873
1874         char old_type, old_status;
1875    fix timevar;
1876    int i;
1877
1878         mprintf((0, "Sending game info.\n"));
1879
1880         network_update_netgame(); // Update the values in the netgame struct
1881
1882         old_type = Netgame.type;
1883         old_status = Netgame.game_status;
1884
1885         Netgame.type = PID_GAME_INFO;
1886    NetPlayers.type = PID_PLAYERSINFO;
1887
1888    NetPlayers.Security=Netgame.Security;
1889         Netgame.version_major=Version_major;
1890         Netgame.version_minor=Version_minor;
1891
1892         if (Endlevel_sequence || Control_center_destroyed)
1893                 Netgame.game_status = NETSTAT_ENDLEVEL;
1894
1895         if (Netgame.PlayTimeAllowed)
1896     {
1897                 timevar=i2f (Netgame.PlayTimeAllowed*5*60);
1898                 i=f2i(timevar-ThisLevelTime);
1899                 if (i<30)
1900                         Netgame.game_status=NETSTAT_ENDLEVEL;
1901         }       
1902
1903         if (!their) {
1904                 if (Network_game_type == IPX_GAME) {
1905                         #ifndef MACINTOSH
1906                         ipx_send_broadcast_packet_data((ubyte *)&Netgame, sizeof(netgame_info));
1907                         ipx_send_broadcast_packet_data((ubyte *)&NetPlayers,sizeof(AllNetPlayers_info));
1908                         #else
1909                         send_netgame_packet(NULL, NULL, NULL, 0);               // server == NULL says to broadcast packet
1910                         send_netplayers_packet(NULL, NULL);
1911                         #endif
1912                 } // nothing to do for appletalk games I think....
1913         } else {
1914                 if (Network_game_type == IPX_GAME) {
1915                         #ifndef MACINTOSH        
1916                     ipx_send_internetwork_packet_data((ubyte *)&Netgame, sizeof(netgame_info), their->player.network.ipx.server, their->player.network.ipx.node);
1917                         ipx_send_internetwork_packet_data((ubyte *)&NetPlayers,sizeof(AllNetPlayers_info),their->player.network.ipx.server,their->player.network.ipx.node);
1918                         #else
1919                         send_netgame_packet(their->player.network.ipx.server, their->player.network.ipx.node, NULL, 0);
1920                         send_netplayers_packet(their->player.network.ipx.server, their->player.network.ipx.node);
1921                         #endif
1922                 #ifdef MACINTOSH
1923                 } else {
1924                         appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), their->player.network.appletalk.node,
1925                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1926                         appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), their->player.network.appletalk.node,
1927                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1928                 #endif
1929                 }
1930         }  
1931
1932         Netgame.type = old_type;
1933         Netgame.game_status = old_status;
1934 }       
1935
1936 void network_send_lite_info(sequence_packet *their)
1937 {
1938         // Send game info to someone who requested it
1939
1940         char old_type, old_status,oldstatus;
1941
1942         mprintf((0, "Sending lite game info.\n"));
1943
1944         network_update_netgame(); // Update the values in the netgame struct
1945
1946         old_type = Netgame.type;
1947         old_status = Netgame.game_status;
1948
1949         Netgame.type = PID_LITE_INFO;
1950
1951         if (Endlevel_sequence || Control_center_destroyed)
1952                 Netgame.game_status = NETSTAT_ENDLEVEL;
1953
1954 // If hoard mode, make this game look closed even if it isn't
1955    if (HoardEquipped())
1956         {
1957                 if (Game_mode & GM_HOARD)
1958                 {
1959                         oldstatus=Netgame.game_status;
1960                         Netgame.game_status=NETSTAT_ENDLEVEL;
1961                         Netgame.gamemode=NETGAME_CAPTURE_FLAG;
1962                         if (oldstatus==NETSTAT_ENDLEVEL)
1963                                 Netgame.game_flags|=NETGAME_FLAG_REALLY_ENDLEVEL;
1964                         if (oldstatus==NETSTAT_STARTING)
1965                                 Netgame.game_flags|=NETGAME_FLAG_REALLY_FORMING;
1966                 }
1967         }
1968
1969         if (!their) {
1970                 if (Network_game_type == IPX_GAME) {
1971                         #ifndef MACINTOSH
1972                         ipx_send_broadcast_packet_data((ubyte *)&Netgame, sizeof(lite_info));
1973                         #else
1974                         send_netgame_packet(NULL, NULL, NULL, 1);                       // server == NULL says broadcast
1975                         #endif
1976                 }               // nothing to do for appletalk I think....
1977         } else {
1978                 if (Network_game_type == IPX_GAME) {
1979                         #ifndef MACINTOSH
1980                     ipx_send_internetwork_packet_data((ubyte *)&Netgame, sizeof(lite_info), their->player.network.ipx.server, their->player.network.ipx.node);
1981                         #else
1982                         send_netgame_packet(their->player.network.ipx.server, their->player.network.ipx.node, NULL, 1);
1983                         #endif
1984                 #ifdef MACINTOSH
1985                 } else {
1986                         appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(lite_info), their->player.network.appletalk.node,
1987                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1988                 #endif
1989                 }
1990         }  
1991
1992         //  Restore the pre-hoard mode
1993         if (HoardEquipped())
1994         {
1995                 if (Game_mode & GM_HOARD)
1996                 {
1997                         if (!(Game_mode & GM_TEAM))
1998                            Netgame.gamemode=NETGAME_HOARD;
1999                         else
2000                            Netgame.gamemode=NETGAME_TEAM_HOARD;
2001                         Netgame.game_flags&=~NETGAME_FLAG_REALLY_ENDLEVEL;
2002                         Netgame.game_flags&=~NETGAME_FLAG_REALLY_FORMING;
2003                         Netgame.game_flags&=~NETGAME_FLAG_TEAM_HOARD;
2004                 }
2005         }
2006
2007         Netgame.type = old_type;
2008         Netgame.game_status = old_status;
2009
2010 }       
2011
2012 void network_send_netgame_update()
2013 {
2014         // Send game info to someone who requested it
2015
2016         char old_type, old_status;
2017         int i;
2018
2019         mprintf((0, "Sending updated game info.\n"));
2020
2021         network_update_netgame(); // Update the values in the netgame struct
2022
2023         old_type = Netgame.type;
2024         old_status = Netgame.game_status;
2025
2026         Netgame.type = PID_GAME_UPDATE;
2027
2028         if (Endlevel_sequence || Control_center_destroyed)
2029                 Netgame.game_status = NETSTAT_ENDLEVEL;
2030  
2031         for (i=0; i<N_players; i++ )    {
2032                 if ( (Players[i].connected) && (i!=Player_num ) )       {
2033                         if (Network_game_type == IPX_GAME) {
2034                                 #ifndef MACINTOSH
2035                                 ipx_send_packet_data( (ubyte *)&Netgame, sizeof(lite_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address );
2036                                 #else
2037                                 send_netgame_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, Players[i].net_address, 0);
2038                                 #endif
2039                         #ifdef MACINTOSH
2040                         } else {
2041                                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(lite_info), NetPlayers.players[i].network.appletalk.node,
2042                                                                                         NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket );
2043                         #endif
2044                         }
2045                 }
2046         }
2047
2048         Netgame.type = old_type;
2049         Netgame.game_status = old_status;
2050 }       
2051                           
2052 int network_send_request(void)
2053 {
2054         // Send a request to join a game 'Netgame'.  Returns 0 if we can join this
2055         // game, non-zero if there is some problem.
2056         int i;
2057
2058         if (Netgame.numplayers < 1)
2059          return 1;
2060
2061         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
2062           if (NetPlayers.players[i].connected)
2063               break;
2064
2065         Assert(i < MAX_NUM_NET_PLAYERS);
2066
2067         mprintf((0, "Sending game enroll request to player %d (%s). Serv=%x Node=%x Level=%d\n", i, Players[i].callsign,NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node,Netgame.levelnum));
2068
2069 //      segments_checksum = netmisc_calc_checksum( Segments, sizeof(segment)*(Highest_segment_index+1) );       
2070
2071         My_Seq.type = PID_REQUEST;
2072         My_Seq.player.connected = Current_level_num;
2073
2074         if (Network_game_type == IPX_GAME) {
2075                 #ifndef MACINTOSH
2076                 ipx_send_internetwork_packet_data((ubyte *)&My_Seq, sizeof(sequence_packet), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
2077                 #else
2078                 send_sequence_packet(My_Seq, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, NULL);
2079                 #endif
2080         #ifdef MACINTOSH
2081         } else {
2082                 appletalk_send_packet_data( (ubyte *)&My_Seq, sizeof(sequence_packet), NetPlayers.players[i].network.appletalk.node,
2083                                                                         NetPlayers.players[i].network.appletalk.net,
2084                                                                         NetPlayers.players[i].network.appletalk.socket);
2085         #endif
2086         }
2087
2088         return i;
2089 }
2090
2091 int SecurityCheck=0;
2092         
2093 void network_process_gameinfo(ubyte *data)
2094 {
2095 #ifdef MACINTOSH
2096         netgame_info tmp_info;
2097 #endif
2098         int i, j;
2099         netgame_info *new = (netgame_info *)data;
2100
2101 #ifdef MACINTOSH
2102         if (Network_game_type == IPX_GAME)  {
2103                 receive_netgame_packet(data, &tmp_info, 0);                     // get correctly aligned structure
2104                 new = &tmp_info;
2105         }
2106 #endif
2107         
2108
2109    WaitingForPlayerInfo=0;
2110
2111    if (new->Security !=TempPlayersInfo->Security)
2112     {
2113      Int3();     // Get Jason
2114      return;     // If this first half doesn't go with the second half
2115     }
2116
2117         Network_games_changed = 1;
2118
2119    //mprintf((0, "Got game data for game %s.\n", new->game_name));
2120
2121    Assert (TempPlayersInfo!=NULL);
2122
2123         for (i = 0; i < num_active_games; i++)
2124          {
2125           //mprintf ((0,"GAMEINFO: Game %d is %s!\n",i,Active_games[i].game_name));
2126           
2127           if (!stricmp(Active_games[i].game_name, new->game_name) && 
2128                                   Active_games[i].Security==new->Security)
2129                break;
2130          }
2131
2132         if (i == MAX_ACTIVE_NETGAMES)
2133         {
2134                 mprintf((0, "Too many netgames.\n"));
2135                 return;
2136         }
2137         
2138 // MWA  memcpy(&Active_games[i], data, sizeof(netgame_info));
2139         memcpy(&Active_games[i], (ubyte *)new, sizeof(netgame_info));
2140         memcpy (&ActiveNetPlayers[i],TempPlayersInfo,sizeof(AllNetPlayers_info));
2141
2142    if (SecurityCheck)
2143          if (Active_games[i].Security==SecurityCheck)
2144                 SecurityCheck=-1;
2145
2146         //mprintf ((0,"Recieved %d unique games...\n",i));
2147
2148         if (i == num_active_games)
2149                 num_active_games++;
2150
2151         if (Active_games[i].numplayers == 0)
2152         {
2153          mprintf ((0,"DELETING THIS GAME!!!\n"));       
2154                 // Delete this game
2155                 for (j = i; j < num_active_games-1; j++)
2156         {
2157              memcpy(&Active_games[j], &Active_games[j+1], sizeof(netgame_info));
2158            memcpy (&ActiveNetPlayers[j],&ActiveNetPlayers[j+1],sizeof(AllNetPlayers_info));
2159         }
2160                 num_active_games--;
2161                 SecurityCheck=0;
2162         }
2163 }
2164
2165 void network_process_lite_info(ubyte *data)
2166 {
2167 #ifdef MACINTOSH
2168         lite_info tmp_info;
2169 #endif
2170         int i, j;
2171         lite_info *new = (lite_info *)data;
2172
2173 #ifdef MACINTOSH
2174         if (Network_game_type == IPX_GAME) {
2175                 receive_netgame_packet(data, (netgame_info *)&tmp_info, 1);
2176                 new = &tmp_info;
2177         }
2178 #endif
2179
2180         Network_games_changed = 1;
2181
2182    //mprintf((0, "Got game data for game %s.\n", new->game_name));
2183
2184         for (i = 0; i < num_active_games; i++)
2185     {
2186       //mprintf ((0,"GAMEINFO: Game %d is %s!\n",i,Active_games[i].game_name));
2187       
2188       if ((!stricmp(Active_games[i].game_name, new->game_name)) && 
2189                          Active_games[i].Security==new->Security)
2190                                 break;
2191     }
2192
2193         if (i == MAX_ACTIVE_NETGAMES)
2194         {
2195                 mprintf((0, "Too many netgames.\n"));
2196                 return;
2197         }
2198         
2199         memcpy(&Active_games[i], (ubyte *)new, sizeof(lite_info));
2200
2201 // See if this is really a Hoard game
2202 // If so, adjust all the data accordingly
2203
2204         if (HoardEquipped())
2205         {
2206                 if (Active_games[i].game_flags & NETGAME_FLAG_HOARD)
2207                 {
2208                         Active_games[i].gamemode=NETGAME_HOARD;                                   
2209                         Active_games[i].game_status=NETSTAT_PLAYING;
2210                         
2211                         if (Active_games[i].game_flags & NETGAME_FLAG_TEAM_HOARD)
2212                                 Active_games[i].gamemode=NETGAME_TEAM_HOARD;                                      
2213                         if (Active_games[i].game_flags & NETGAME_FLAG_REALLY_ENDLEVEL)
2214                                 Active_games[i].game_status=NETSTAT_ENDLEVEL;
2215                         if (Active_games[i].game_flags & NETGAME_FLAG_REALLY_FORMING)
2216                                 Active_games[i].game_status=NETSTAT_STARTING;
2217                 }
2218         }
2219
2220    //mprintf ((0,"Recieved %d unique games...\n",i));
2221
2222         if (i == num_active_games)
2223                 num_active_games++;
2224
2225         if (Active_games[i].numplayers == 0)
2226     {
2227            mprintf ((0,"DELETING THIS GAME!!!\n"));     
2228                 // Delete this game
2229                 for (j = i; j < num_active_games-1; j++)
2230         {
2231              memcpy(&Active_games[j], &Active_games[j+1], sizeof(netgame_info));
2232         }
2233                 num_active_games--;
2234         }
2235 }
2236
2237 void network_process_dump(sequence_packet *their)
2238 {
2239         // Our request for join was denied.  Tell the user why.
2240
2241    char temp[40];
2242    int i;
2243  
2244         mprintf((0, "Dumped by player %s, type %d.\n", their->player.callsign, their->player.connected));
2245
2246    if (their->player.connected!=7)
2247                 nm_messagebox(NULL, 1, TXT_OK, NET_DUMP_STRINGS(their->player.connected));
2248         else
2249                 {
2250                  for (i=0;i<N_players;i++)
2251                         if (!stricmp (their->player.callsign,Players[i].callsign))
2252                         {
2253                                 if (i!=network_who_is_master())
2254                                 {
2255                                         HUD_init_message ("%s attempted to kick you out.",their->player.callsign);
2256                                 }
2257                                 else
2258                                 {
2259                                   sprintf (temp,"%s has kicked you out!",their->player.callsign);
2260                                   nm_messagebox(NULL, 1, TXT_OK, &temp);
2261                             if (Network_status==NETSTAT_PLAYING)
2262                                   {
2263                                         IWasKicked=1;
2264                                         multi_leave_game();     
2265                                   }
2266                                  else
2267                                         Network_status = NETSTAT_MENU;
2268                       }
2269                    }
2270                 }
2271 }       
2272 void network_process_request(sequence_packet *their)
2273 {
2274         // Player is ready to receieve a sync packet
2275         int i;
2276
2277         mprintf((0, "Player %s ready for sync.\n", their->player.callsign));
2278
2279         for (i = 0; i < N_players; i++) {
2280                 if (Network_game_type == IPX_GAME) {
2281                         if (!memcmp(their->player.network.ipx.server, NetPlayers.players[i].network.ipx.server, 4) && !memcmp(their->player.network.ipx.node, NetPlayers.players[i].network.ipx.node, 6) && (!stricmp(their->player.callsign, NetPlayers.players[i].callsign))) {
2282                                 Players[i].connected = 1;
2283                                 break;
2284                         }
2285                 } else {
2286                         if ( (their->player.network.appletalk.node == NetPlayers.players[i].network.appletalk.node) && (their->player.network.appletalk.net == NetPlayers.players[i].network.appletalk.net) && (!stricmp(their->player.callsign, NetPlayers.players[i].callsign)) ) {
2287                                 Players[i].connected = 1;
2288                                 break;
2289                         }
2290                 }
2291         }                       
2292 }
2293
2294 #define REFUSE_INTERVAL F1_0 * 8
2295 extern void multi_reset_object_texture (object *);
2296
2297 void network_process_packet(ubyte *data, int length )
2298 {
2299 #ifdef MACINTOSH
2300         sequence_packet tmp_packet;
2301 #endif
2302         sequence_packet *their = (sequence_packet *)data;
2303
2304 #ifdef MACINTOSH
2305         if (Network_game_type == IPX_GAME) {
2306                 receive_sequence_packet(data, &tmp_packet);
2307                 their = &tmp_packet;                                            // reassign their to point to correctly alinged structure
2308         }
2309 #endif
2310
2311    //mprintf( (0, "Got packet of length %d, type %d\n", length, their->type ));
2312         
2313 //      if ( length < sizeof(sequence_packet) ) return;
2314
2315         length = length;
2316
2317         switch( data[0] )       {
2318         
2319          case PID_GAME_INFO:            // Jason L. says we can safely ignore this type.
2320                 break;
2321         
2322      case PID_PLAYERSINFO:
2323
2324                 mprintf ((0,"Got a PID_PLAYERSINFO!\n"));
2325
2326                 if (Network_status==NETSTAT_WAITING)
2327                 {
2328 #ifndef MACINTOSH                        
2329                         memcpy (&TempPlayersBase,data,sizeof(AllNetPlayers_info));
2330 #else
2331                         if (Network_game_type == IPX_GAME)
2332                                 receive_netplayers_packet(data, &TempPlayersBase);
2333                         else
2334                                 memcpy (&TempPlayersBase,data,sizeof(AllNetPlayers_info));
2335 #endif
2336
2337                         if (TempPlayersBase.Security!=Netgame.Security)
2338                          {
2339                           mprintf ((0,"Bad security for PLAYERSINFO\n"));
2340                           break;
2341                          }      
2342                 
2343                         mprintf ((0,"Got a waiting PID_PLAYERSINFO!\n"));
2344                         if (length!=ALLNETPLAYERSINFO_SIZE)
2345                         {
2346                                 mprintf ((0,"Invalid size for netplayers packet!\n"));
2347                                 return;
2348                         }
2349
2350                         TempPlayersInfo=&TempPlayersBase;
2351                         WaitingForPlayerInfo=0;
2352                         NetSecurityNum=TempPlayersInfo->Security;
2353                         NetSecurityFlag=NETSECURITY_WAIT_FOR_SYNC;
2354            }
2355
2356      break;
2357
2358    case PID_LITE_INFO:
2359
2360          if (length != LITE_INFO_SIZE)
2361                  {
2362                   mprintf ((0,"WARNING! Recieved invalid size for PID_LITE_INFO\n"));
2363                   return;
2364                  }
2365  
2366          if (Network_status == NETSTAT_BROWSING)
2367                 network_process_lite_info (data);
2368     break;
2369
2370         case PID_GAME_LIST:
2371                 // Someone wants a list of games
2372
2373            if (length != SEQUENCE_PACKET_SIZE)
2374                  {
2375                   mprintf ((0,"WARNING! Recieved invalid size for PID_GAME_LIST\n"));
2376                   return;
2377                  }
2378                         
2379                 mprintf((0, "Got a PID_GAME_LIST!\n"));
2380                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2381                         if (network_i_am_master())
2382                                 network_send_lite_info(their);
2383                 break;
2384
2385
2386         case PID_SEND_ALL_GAMEINFO:
2387
2388            if (length != SEQUENCE_PACKET_SIZE)
2389                  {
2390                   mprintf ((0,"WARNING! Recieved invalid size for PID_SEND_ALL_GAMEINFO\n"));
2391                   return;
2392                  }
2393
2394                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2395                         if (network_i_am_master() && their->Security==Netgame.Security)
2396                                 network_send_game_info(their);
2397                 break;
2398         
2399         case PID_ADDPLAYER:
2400
2401                 mprintf( (0, "Got NEWPLAYER message from %s.\n", their->player.callsign));
2402                 
2403            if (length != SEQUENCE_PACKET_SIZE)
2404                  {
2405                   mprintf ((0,"WARNING! Recieved invalid size for PID_ADDPLAYER\n"));
2406                   return;
2407                  }
2408                 mprintf( (0, "Got NEWPLAYER message from %s.\n", their->player.callsign));
2409                 network_new_player(their);
2410                 break;                  
2411         case PID_REQUEST:
2412            if (length != SEQUENCE_PACKET_SIZE)
2413                  {
2414                   mprintf ((0,"WARNING! Recieved invalid size for PID_REQUEST\n"));
2415                   return;
2416                  }
2417
2418                 mprintf( (0, "Got REQUEST from '%s'\n", their->player.callsign ));
2419                 if (Network_status == NETSTAT_STARTING) 
2420                 {
2421                         // Someone wants to join our game!
2422                         network_add_player(their);
2423                 }
2424                 else if (Network_status == NETSTAT_WAITING)
2425                 {
2426                         // Someone is ready to recieve a sync packet
2427                         network_process_request(their);
2428                 }
2429                 else if (Network_status == NETSTAT_PLAYING)
2430                 {
2431                         // Someone wants to join a game in progress!
2432                         if (Netgame.RefusePlayers)
2433                 DoRefuseStuff (their);
2434                    else 
2435                                 network_welcome_player(their);
2436                 }
2437                 break;
2438         case PID_DUMP:  
2439
2440            if (length != SEQUENCE_PACKET_SIZE)
2441                  {
2442                   mprintf ((0,"WARNING! Recieved invalid size for PID_DUMP\n"));
2443                   return;
2444                  }
2445   
2446                 if (Network_status == NETSTAT_WAITING || Network_status==NETSTAT_PLAYING )
2447                         network_process_dump(their);
2448                 break;
2449         case PID_QUIT_JOINING:
2450
2451            if (length != SEQUENCE_PACKET_SIZE)
2452                  {
2453                   mprintf ((0,"WARNING! Recieved invalid size for PID_QUIT_JOINING\n"));
2454                   return;
2455                  }
2456                 if (Network_status == NETSTAT_STARTING)
2457                         network_remove_player( their );
2458                 else if ((Network_status == NETSTAT_PLAYING) && (Network_send_objects))
2459                         network_stop_resync( their );
2460                 break;
2461         case PID_SYNC:  
2462
2463                 mprintf ((0,"Got a sync packet! Network_status=%d\n",NETSTAT_WAITING));
2464
2465                 if (Network_status == NETSTAT_WAITING)  {
2466
2467 #ifndef MACINTOSH
2468                         memcpy((ubyte *)&(TempNetInfo), data, sizeof(netgame_info));
2469 #else
2470                         if (Network_game_type == IPX_GAME)
2471                                 receive_netgame_packet(data, &TempNetInfo, 0);
2472                         else
2473                                 memcpy((ubyte *)&(TempNetInfo), data, sizeof(netgame_info));
2474 #endif
2475
2476                         if (TempNetInfo.Security!=Netgame.Security)
2477                          {
2478                                 mprintf ((0,"Bad security on sync packet.\n"));
2479                                 break;
2480                          }
2481
2482                         if (NetSecurityFlag==NETSECURITY_WAIT_FOR_SYNC)
2483                          {
2484                           if (TempNetInfo.Security==TempPlayersInfo->Security)
2485                           {
2486                                 network_read_sync_packet (&TempNetInfo,0);
2487                                 NetSecurityFlag=0;
2488                                 NetSecurityNum=0;
2489                           }     
2490                          }
2491                         else
2492                          {      
2493                         NetSecurityFlag=NETSECURITY_WAIT_FOR_PLAYERS;
2494                         NetSecurityNum=TempNetInfo.Security;
2495
2496                         if ( network_wait_for_playerinfo())
2497                                 network_read_sync_packet((netgame_info *)data,0);
2498  
2499                         NetSecurityFlag=0;
2500                         NetSecurityNum=0;
2501                          }
2502                 }
2503                 break;
2504
2505         case PID_PDATA: 
2506                 if ((Game_mode&GM_NETWORK) && ((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) || Network_status==NETSTAT_WAITING)) { 
2507                         network_process_pdata((char *)data);
2508                 }
2509                 break;
2510    case PID_NAKED_PDATA:
2511                 if ((Game_mode&GM_NETWORK) && ((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) || Network_status==NETSTAT_WAITING)) 
2512                         network_process_naked_pdata((char *)data,length);
2513            break;
2514
2515         case PID_OBJECT_DATA:
2516                 if (Network_status == NETSTAT_WAITING) 
2517                         network_read_object_packet(data);
2518                 break;
2519         case PID_ENDLEVEL:
2520                 if ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))
2521                         network_read_endlevel_packet(data);
2522                 else
2523                         mprintf((0, "Junked endlevel packet.\n"));
2524                 break;
2525         case PID_ENDLEVEL_SHORT:
2526                 if ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))
2527                         network_read_endlevel_short_packet(data);
2528                 else
2529                         mprintf((0, "Junked short endlevel packet!\n"));
2530                 break;
2531
2532         case PID_GAME_UPDATE:
2533                 mprintf ((0,"Got a GAME_UPDATE!\n"));
2534                         
2535                 if (Network_status==NETSTAT_PLAYING)
2536                  {
2537 #ifndef MACINTOSH
2538                         memcpy((ubyte *)&TempNetInfo, data, sizeof(lite_info) );
2539 #else
2540                         if (Network_game_type == IPX_GAME)
2541                                 receive_netgame_packet(data, &TempNetInfo, 1);
2542                         else
2543                                 memcpy((ubyte *)&TempNetInfo, data, sizeof(lite_info) );
2544 #endif
2545                   if (TempNetInfo.Security==Netgame.Security)
2546                          memcpy (&Netgame,(ubyte *)&TempNetInfo,sizeof(lite_info));
2547                  }
2548                 if (Game_mode & GM_TEAM)
2549                  {
2550                         int i;
2551
2552                         for (i=0;i<N_players;i++)
2553                          if (Players[i].connected)
2554                         multi_reset_object_texture (&Objects[Players[i].objnum]);
2555                     reset_cockpit();
2556                  }
2557            break;
2558    case PID_PING_SEND:
2559                 network_ping (PID_PING_RETURN,data[1]);
2560                 break;
2561    case PID_PING_RETURN:
2562                 network_handle_ping_return(data[1]);  // data[1] is player who told us of their ping time
2563                 break;
2564    case PID_NAMES_RETURN:
2565                 if (Network_status==NETSTAT_BROWSING && NamesInfoSecurity!=-1)
2566                   network_process_names_return (data);
2567                 break;
2568         case PID_GAME_PLAYERS:
2569                 // Someone wants a list of players in this game
2570
2571            if (length != SEQUENCE_PACKET_SIZE)
2572                  {
2573                   mprintf ((0,"WARNING! Recieved invalid size for PID_GAME_PLAYERS\n"));
2574                   return;
2575                  }
2576                         
2577                 mprintf((0, "Got a PID_GAME_PLAYERS!\n"));
2578                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2579                         if (network_i_am_master() && their->Security==Netgame.Security)
2580                                 network_send_player_names(their);
2581                 break;
2582
2583         default:
2584                 mprintf((0, "Ignoring invalid packet type.\n"));
2585                 Int3(); // Invalid network packet type, see ROB
2586            break;
2587         }
2588 }
2589
2590 #ifndef NDEBUG
2591 void dump_segments()
2592 {
2593         FILE * fp;
2594
2595         fp = fopen( "TEST.DMP", "wb" );
2596         fwrite( Segments, sizeof(segment)*(Highest_segment_index+1),1, fp );    
2597         fclose(fp);
2598         mprintf( (0, "SS=%d\n", sizeof(segment) ));
2599 }
2600 #endif
2601
2602
2603 void
2604 network_read_endlevel_packet( ubyte *data )
2605 {
2606         // Special packet for end of level syncing
2607 #ifdef MACINTOSH
2608         int i, j;
2609 #endif
2610         int playernum;
2611         endlevel_info *end;     
2612
2613         end = (endlevel_info *)data;
2614 #ifdef MACINTOSH
2615         for (i = 0; i < MAX_PLAYERS; i++)
2616                 for (j = 0; j < MAX_PLAYERS; j++)
2617                         end->kill_matrix[i][j] = INTEL_SHORT(end->kill_matrix[i][j]);
2618         end->kills = INTEL_SHORT(end->kills);
2619         end->killed = INTEL_SHORT(end->killed);
2620 #endif
2621
2622         playernum = end->player_num;
2623         
2624         Assert(playernum != Player_num);
2625     
2626         if (playernum>=N_players)
2627          {              
2628                 Int3(); // weird, but it an happen in a coop restore game
2629                 return; // if it happens in a coop restore, don't worry about it
2630          }
2631
2632         if ((Network_status == NETSTAT_PLAYING) && (end->connected != 0))
2633                 return; // Only accept disconnect packets if we're not out of the level yet
2634
2635         Players[playernum].connected = end->connected;
2636         memcpy(&kill_matrix[playernum][0], end->kill_matrix, MAX_PLAYERS*sizeof(short));
2637         Players[playernum].net_kills_total = end->kills;
2638         Players[playernum].net_killed_total = end->killed;
2639
2640         if ((Players[playernum].connected == 1) && (end->seconds_left < Countdown_seconds_left))
2641                 Countdown_seconds_left = end->seconds_left;
2642
2643         LastPacketTime[playernum] = timer_get_approx_seconds();
2644
2645 //      mprintf((0, "Got endlevel packet from player %d.\n", playernum));
2646 }
2647
2648 void
2649 network_read_endlevel_short_packet( ubyte *data )
2650 {
2651         // Special packet for end of level syncing
2652
2653         int playernum;
2654         endlevel_info_short *end;       
2655
2656         end = (endlevel_info_short *)data;
2657
2658         playernum = end->player_num;
2659         
2660         Assert(playernum != Player_num);
2661     
2662         if (playernum>=N_players)
2663          {              
2664                 Int3(); // weird, but it can happen in a coop restore game
2665                 return; // if it happens in a coop restore, don't worry about it
2666          }
2667
2668         if ((Network_status == NETSTAT_PLAYING) && (end->connected != 0))
2669          {
2670                 //mprintf ((0,"Returning early for short_endlevel\n"));
2671                 return; // Only accept disconnect packets if we're not out of the level yet
2672          }
2673
2674         Players[playernum].connected = end->connected;
2675
2676         if ((Players[playernum].connected == 1) && (end->seconds_left < Countdown_seconds_left))
2677                 Countdown_seconds_left = end->seconds_left;
2678
2679         LastPacketTime[playernum] = timer_get_approx_seconds();
2680 }
2681
2682
2683 void
2684 network_pack_objects(void)
2685 {
2686         // Switching modes, pack the object array
2687
2688         special_reset_objects();
2689 }                               
2690
2691 int
2692 network_verify_objects(int remote, int local)
2693 {
2694         int i;
2695         int nplayers, got_controlcen=0;
2696
2697    mprintf ((0,"NETWORK:remote=%d local=%d\n",remote,local));
2698
2699         if ((remote-local) > 10)
2700                 return(-1);
2701
2702         if (Game_mode & GM_MULTI_ROBOTS)
2703                 got_controlcen = 1;
2704
2705         nplayers = 0;
2706
2707         for (i = 0; i <= Highest_object_index; i++)
2708         {
2709                 if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST))
2710                         nplayers++;
2711                 if (Objects[i].type == OBJ_CNTRLCEN)
2712                         got_controlcen=1;
2713         }
2714
2715     if (got_controlcen && (MaxNumNetPlayers<=nplayers))
2716                 return(0);
2717
2718         return(1);
2719 }
2720         
2721 void
2722 network_read_object_packet( ubyte *data )
2723 {
2724         // Object from another net player we need to sync with
2725
2726         short objnum, remote_objnum;
2727         byte obj_owner;
2728         int segnum, i;
2729         object *obj;
2730
2731         static int my_pnum = 0;
2732         static int mode = 0;
2733         static int object_count = 0;
2734         static int frame_num = 0;
2735         int nobj = data[1];
2736         int loc = 3;
2737         int remote_frame_num = data[2];
2738         
2739         frame_num++;
2740
2741 //      mprintf((0, "Object packet %d (remote #%d) contains %d objects.\n", frame_num, remote_frame_num, nobj));
2742
2743         for (i = 0; i < nobj; i++)
2744         {
2745                 objnum = INTEL_SHORT( *(short *)(data+loc) );                   loc += 2;
2746                 obj_owner = data[loc];                                                                  loc += 1;
2747                 remote_objnum = INTEL_SHORT( *(short *)(data+loc) );    loc += 2;
2748
2749                 if (objnum == -1) 
2750                 {
2751                         // Clear object array
2752                         mprintf((0, "Clearing object array.\n"));
2753
2754                         init_objects();
2755                         Network_rejoined = 1;
2756                         my_pnum = obj_owner;
2757                         change_playernum_to(my_pnum);
2758                         mode = 1;
2759                         object_count = 0;
2760                         frame_num = 1;
2761                 }
2762                 else if (objnum == -2)
2763                 {
2764                         // Special debug checksum marker for entire send
2765                         if (mode == 1)
2766                         {
2767                                 network_pack_objects();
2768                                 mode = 0;
2769                         }
2770                         mprintf((0, "Objnum -2 found in frame local %d remote %d.\n", frame_num, remote_frame_num));
2771                         mprintf((0, "Got %d objects, expected %d.\n", object_count, remote_objnum));
2772                         if (remote_objnum != object_count) {
2773                                 Int3();
2774                         }
2775                         if (network_verify_objects(remote_objnum, object_count))
2776                         {
2777                                 // Failed to sync up 
2778                                 nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED);
2779                                 Network_status = NETSTAT_MENU;                          
2780                                 return;
2781                         }
2782                         frame_num = 0;
2783                 }
2784                 else 
2785                 {
2786                         if (frame_num != remote_frame_num)
2787                                 Int3();
2788                         mprintf ((0,"Got a type 3 object packet!\n"));
2789                         object_count++;
2790                         if ((obj_owner == my_pnum) || (obj_owner == -1)) 
2791                         {
2792                                 if (mode != 1)
2793                                         Int3(); // SEE ROB
2794                                 objnum = remote_objnum;
2795                                 //if (objnum > Highest_object_index)
2796                                 //{
2797                                 //      Highest_object_index = objnum;
2798                                 //      num_objects = Highest_object_index+1;
2799                                 //}
2800                         }
2801                         else {
2802                                 if (mode == 1)
2803                                 {
2804                                         network_pack_objects();
2805                                         mode = 0;
2806                                 }
2807                                 objnum = obj_allocate();
2808                         }
2809                         if (objnum != -1) {
2810                                 obj = &Objects[objnum];
2811                                 if (obj->segnum != -1)
2812                                         obj_unlink(objnum);
2813                                 Assert(obj->segnum == -1);
2814                                 Assert(objnum < MAX_OBJECTS);
2815                                 memcpy(obj,data+loc,sizeof(object));            loc += sizeof(object);
2816 #ifdef MACINTOSH
2817                                 if (Network_game_type == IPX_GAME)
2818                                         swap_object(obj);
2819 #endif
2820                                 segnum = obj->segnum;
2821                                 obj->next = obj->prev = obj->segnum = -1;
2822                                 obj->attached_obj = -1;
2823                                 if (segnum > -1)
2824                                         obj_link(obj-Objects,segnum);
2825                                 if (obj_owner == my_pnum) 
2826                                         map_objnum_local_to_local(objnum);
2827                                 else if (obj_owner != -1)
2828                                         map_objnum_local_to_remote(objnum, remote_objnum, obj_owner);
2829                                 else
2830                                         object_owner[objnum] = -1;
2831                         }
2832                 } // For a standard onbject
2833         } // For each object in packet
2834 }
2835         
2836 void network_sync_poll( int nitems, newmenu_item * menus, int * key, int citem )
2837 {
2838         // Polling loop waiting for sync packet to start game
2839
2840         static fix t1 = 0;
2841
2842         menus = menus;
2843         citem = citem;
2844         nitems = nitems;
2845
2846         network_listen();
2847
2848         if (Network_status != NETSTAT_WAITING)  // Status changed to playing, exit the menu
2849                 *key = -2;
2850
2851         if (!Network_rejoined && (timer_get_approx_seconds() > t1+F1_0*2))
2852         {
2853                 int i;
2854
2855                 // Poll time expired, re-send request
2856                 
2857                 t1 = timer_get_approx_seconds();
2858
2859                 mprintf((0, "Re-sending join request.\n"));
2860                 i = network_send_request();
2861                 if (i < 0)
2862                         *key = -2;
2863         }
2864 }
2865
2866 void network_start_poll( int nitems, newmenu_item * menus, int * key, int citem )
2867 {
2868         int i,n,nm;
2869
2870         key=key;
2871         citem=citem;
2872
2873         Assert(Network_status == NETSTAT_STARTING);
2874
2875         if (!menus[0].value) {
2876                         menus[0].value = 1;
2877                         menus[0].redraw = 1;
2878         }
2879
2880         for (i=1; i<nitems; i++ )       {
2881                 if ( (i>= N_players) && (menus[i].value) )      {
2882                         menus[i].value = 0;
2883                         menus[i].redraw = 1;
2884                 }
2885         }
2886
2887         nm = 0;
2888         for (i=0; i<nitems; i++ )       {
2889                 if ( menus[i].value )   {
2890                         nm++;
2891                         if ( nm > N_players )   {
2892                                 menus[i].value = 0;
2893                                 menus[i].redraw = 1;
2894                         }
2895                 }
2896         }
2897
2898         if ( nm > MaxNumNetPlayers )    {
2899                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
2900                 // Turn off the last player highlighted
2901                 for (i = N_players; i > 0; i--)
2902                         if (menus[i].value == 1) 
2903                         {
2904                                 menus[i].value = 0;
2905                                 menus[i].redraw = 1;
2906                                 break;
2907                         }
2908         }
2909
2910 //       if (nitems > MAX_PLAYERS ) return; 
2911         
2912         n = Netgame.numplayers;
2913         network_listen();
2914
2915         if (n < Netgame.numplayers )    
2916         {
2917                 digi_play_sample (SOUND_HUD_MESSAGE,F1_0);
2918
2919       mprintf ((0,"More players are printed!"));
2920                 if (FindArg("-norankings"))
2921               sprintf( menus[N_players-1].text, "%d. %-20s", N_players,NetPlayers.players[N_players-1].callsign );
2922                 else
2923               sprintf( menus[N_players-1].text, "%d. %s%-20s", N_players, RankStrings[NetPlayers.players[N_players-1].rank],NetPlayers.players[N_players-1].callsign );
2924
2925                 menus[N_players-1].redraw = 1;
2926                 if (N_players <= MaxNumNetPlayers)
2927                 {
2928                         menus[N_players-1].value = 1;
2929                 }
2930         } 
2931         else if ( n > Netgame.numplayers )      
2932         {
2933                 // One got removed...
2934
2935       digi_play_sample (SOUND_HUD_KILL,F1_0);
2936   
2937                 for (i=0; i<N_players; i++ )    
2938                 {
2939          
2940          if (FindArg("-norankings"))    
2941                  sprintf( menus[i].text, "%d. %-20s", i+1, NetPlayers.players[i].callsign );
2942          else
2943                  sprintf( menus[i].text, "%d. %s%-20s", i+1, RankStrings[NetPlayers.players[i].rank],NetPlayers.players[i].callsign );
2944                         if (i < MaxNumNetPlayers)
2945                                 menus[i].value = 1;
2946                         else
2947                                 menus[i].value = 0;
2948                         menus[i].redraw = 1;
2949                 }
2950                 for (i=N_players; i<n; i++ )    
2951                 {
2952                         sprintf( menus[i].text, "%d. ", i+1 );          // Clear out the deleted entries...
2953                         menus[i].value = 0;
2954                         menus[i].redraw = 1;
2955                 }
2956    }
2957 }
2958
2959 int opt_cinvul, opt_team_anarchy, opt_coop, opt_show_on_map, opt_closed,opt_maxnet;
2960 int last_cinvul=0,last_maxnet,opt_team_hoard;
2961 int opt_refuse,opt_capture;
2962
2963 void network_game_param_poll( int nitems, newmenu_item * menus, int * key, int citem )
2964 {
2965         static int oldmaxnet=0;
2966
2967         if (((HoardEquipped() && menus[opt_team_hoard].value) || (menus[opt_team_anarchy].value || menus[opt_capture].value)) && !menus[opt_closed].value && !menus[opt_refuse].value) { 
2968                 menus[opt_refuse].value = 1;
2969                 menus[opt_refuse].redraw = 1;
2970                 menus[opt_refuse-1].value = 0;
2971                 menus[opt_refuse-1].redraw = 1;
2972                 menus[opt_refuse-2].value = 0;
2973                 menus[opt_refuse-2].redraw = 1;
2974         }
2975
2976         #ifndef MACINTOSH
2977         if (menus[opt_coop].value)
2978         #else
2979         if ( (menus[opt_coop].value) || ((Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) && (menus[opt_coop-1].value)) )
2980         #endif
2981         {
2982                 oldmaxnet=1;
2983
2984                 if (menus[opt_maxnet].value>2) 
2985                 {
2986                     menus[opt_maxnet].value=2;
2987                     menus[opt_maxnet].redraw=1;
2988                 }
2989
2990                 if (menus[opt_maxnet].max_value>2)
2991                 {
2992                     menus[opt_maxnet].max_value=2;
2993                     menus[opt_maxnet].redraw=1;
2994                 }
2995
2996                 #ifdef MACINTOSH
2997                 if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
2998                         if (menus[opt_maxnet].value > 0) {
2999                             menus[opt_maxnet].value=0;
3000                             menus[opt_maxnet].redraw=1;
3001                         }
3002                         if (menus[opt_maxnet].max_value > 0) {
3003                                 menus[opt_maxnet].max_value=0;
3004                                 menus[opt_maxnet].redraw=1;
3005                         }
3006                 }
3007                 #endif
3008
3009              if (!Netgame.game_flags & NETGAME_FLAG_SHOW_MAP) 
3010                         Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP;
3011
3012                 if (Netgame.PlayTimeAllowed || Netgame.KillGoal)
3013                 {
3014                     Netgame.PlayTimeAllowed=0;
3015                     Netgame.KillGoal=0;
3016                 }
3017
3018         }
3019         else // if !Coop game
3020     {
3021                 if (oldmaxnet)
3022                 {
3023                     oldmaxnet=0;
3024                         menus[opt_maxnet].value=6;
3025                         menus[opt_maxnet].max_value=6;
3026
3027                     #ifdef MACINTOSH
3028                         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
3029                                 menus[opt_maxnet].value=1;
3030                                 menus[opt_maxnet].max_value=1;
3031                         }
3032                         #endif
3033                           
3034                 }
3035         }         
3036
3037     if ( last_maxnet != menus[opt_maxnet].value )   
3038         {
3039                 sprintf( menus[opt_maxnet].text, "Maximum players: %d", menus[opt_maxnet].value+2 );
3040                 last_maxnet = menus[opt_maxnet].value;
3041                 menus[opt_maxnet].redraw = 1;
3042         }               
3043  }
3044
3045 int netgame_difficulty;
3046
3047 int network_get_game_params( char * game_name, int *mode, int *game_flags, int *level )
3048 {
3049         int i;
3050    int opt, opt_name, opt_level, opt_mode,opt_moreopts;
3051         newmenu_item m[20];
3052         char name[NETGAME_NAME_LEN+1];
3053         char slevel[5];
3054         char level_text[32];
3055    char srmaxnet[50];
3056
3057         int new_mission_num;
3058         int anarchy_only;
3059             
3060    *game_flags=*game_flags;
3061
3062    SetAllAllowablesTo (1);
3063    NamesInfoSecurity=-1;
3064
3065         for (i=0;i<MAX_PLAYERS;i++)
3066          if (i!=Player_num)     
3067                 Players[i].callsign[0]=0;    
3068
3069         MaxNumNetPlayers=8;
3070    Netgame.KillGoal=0;
3071    Netgame.PlayTimeAllowed=0;
3072         Netgame.Allow_marker_view=1;
3073         netgame_difficulty=Player_default_difficulty;
3074
3075         new_mission_num = multi_choose_mission(&anarchy_only);
3076
3077         if (new_mission_num < 0)
3078                 return -1;
3079
3080    if (!(FindArg ("-packets") && FindArg ("-shortpackets")))
3081            if (!network_choose_connect ())
3082                         return -1;
3083
3084         #ifdef MACINTOSH
3085         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) )
3086                 MaxNumNetPlayers = 3;
3087         #endif
3088         
3089         strcpy(Netgame.mission_name, Mission_list[new_mission_num].filename);
3090         strcpy(Netgame.mission_title, Mission_list[new_mission_num].mission_name);
3091         Netgame.control_invul_time = control_invul_time;
3092         
3093         sprintf( name, "%s%s", Players[Player_num].callsign, TXT_S_GAME );
3094         sprintf( slevel, "1" );
3095
3096         opt = 0;
3097         m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_DESCRIPTION; opt++;
3098
3099         opt_name = opt;
3100         m[opt].type = NM_TYPE_INPUT; m[opt].text = name; m[opt].text_len = NETGAME_NAME_LEN; opt++;
3101
3102         sprintf(level_text, "%s (1-%d)", TXT_LEVEL_, Last_level);
3103
3104 //      if (Last_secret_level < -1)
3105 //              sprintf(level_text+strlen(level_text)-1, ", S1-S%d)", -Last_secret_level);
3106 //      else if (Last_secret_level == -1)
3107 //              sprintf(level_text+strlen(level_text)-1, ", S1)");
3108
3109         Assert(strlen(level_text) < 32);
3110
3111         m[opt].type = NM_TYPE_TEXT; m[opt].text = level_text; opt++;
3112
3113         opt_level = opt;
3114         m[opt].type = NM_TYPE_INPUT; m[opt].text = slevel; m[opt].text_len=4; opt++;
3115 //      m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_OPTIONS; opt++;
3116         
3117         opt_mode = opt;
3118         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY; m[opt].value=1; m[opt].group=0; opt++;
3119         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_TEAM_ANARCHY; m[opt].value=0; m[opt].group=0; opt_team_anarchy=opt; opt++;
3120         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY_W_ROBOTS; m[opt].value=0; m[opt].group=0; opt++;
3121         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_COOPERATIVE; m[opt].value=0; m[opt].group=0; opt_coop=opt; opt++;
3122         m[opt].type = NM_TYPE_RADIO; m[opt].text = "Capture the flag"; m[opt].value=0; m[opt].group=0; opt_capture=opt; opt++;
3123    
3124         if (HoardEquipped())
3125         {
3126                 m[opt].type = NM_TYPE_RADIO; m[opt].text = "Hoard"; m[opt].value=0; m[opt].group=0; opt++;
3127                 m[opt].type = NM_TYPE_RADIO; m[opt].text = "Team Hoard"; m[opt].value=0; m[opt].group=0; opt_team_hoard=opt; opt++;
3128            m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++;
3129         } 
3130         else
3131          {  m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++; }
3132
3133         m[opt].type = NM_TYPE_RADIO; m[opt].text = "Open game"; m[opt].group=1; m[opt].value=0; opt++;
3134         opt_closed = opt;
3135         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_CLOSED_GAME; m[opt].group=1; m[opt].value=0; opt++;
3136    opt_refuse = opt;
3137    m[opt].type = NM_TYPE_RADIO; m[opt].text = "Restricted Game              "; m[opt].group=1; m[opt].value=Netgame.RefusePlayers; opt++;
3138
3139 //      m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_IDS; m[opt].value=0; opt++;
3140
3141    opt_maxnet = opt;
3142    sprintf( srmaxnet, "Maximum players: %d", MaxNumNetPlayers);
3143    m[opt].type = NM_TYPE_SLIDER; m[opt].value=MaxNumNetPlayers-2; m[opt].text= srmaxnet; m[opt].min_value=0; 
3144    m[opt].max_value=MaxNumNetPlayers-2; opt++;
3145    last_maxnet=MaxNumNetPlayers-2;
3146
3147    opt_moreopts=opt;
3148    m[opt].type = NM_TYPE_MENU;  m[opt].text = "More options..."; opt++;
3149
3150         Assert(opt <= 20);
3151
3152 menu:
3153    ExtGameStatus=GAMESTAT_NETGAME_OPTIONS; 
3154         i = newmenu_do1( NULL, NULL, opt, m, network_game_param_poll, 1 );
3155                                                                         //TXT_NETGAME_SETUP
3156    if (i==opt_moreopts)
3157     {
3158      if ( m[opt_mode+3].value )
3159       Game_mode=GM_MULTI_COOP;
3160      network_more_game_options();
3161      Game_mode=0;
3162      goto menu;
3163     }
3164   Netgame.RefusePlayers=m[opt_refuse].value;
3165
3166
3167         if ( i > -1 )   {
3168                 int j;
3169                       
3170    MaxNumNetPlayers = m[opt_maxnet].value+2;
3171    Netgame.max_numplayers=MaxNumNetPlayers;
3172                                 
3173                 for (j = 0; j < num_active_games; j++)
3174                         if (!stricmp(Active_games[j].game_name, name))
3175                         {
3176                                 nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_DUPLICATE_NAME);
3177                                 goto menu;
3178                         }
3179
3180                 strcpy( game_name, name );
3181                 
3182
3183                 *level = atoi(slevel);
3184
3185                 if ((*level < 1) || (*level > Last_level))
3186                 {
3187                         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE );
3188                         sprintf(slevel, "1");
3189                         goto menu;
3190                 }
3191                 if ( m[opt_mode].value )
3192                         *mode = NETGAME_ANARCHY;
3193
3194 #ifdef SHAREWARE
3195                 else 
3196                 {
3197                         nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_REGISTERED_ONLY );
3198                         m[opt_mode+1].value = 0;
3199                         m[opt_mode+2].value = 0;
3200                         m[opt_mode+3].value = 0;
3201                    if (HoardEquipped())
3202                                 m[opt_mode+4].value = 0;
3203
3204                         m[opt_mode].value = 1;
3205                         goto menu;
3206                 }
3207 #else
3208                 else if (m[opt_mode+1].value) {
3209                         *mode = NETGAME_TEAM_ANARCHY;
3210                 }
3211                 else if (m[opt_capture].value)
3212                         *mode = NETGAME_CAPTURE_FLAG;
3213                 else if (HoardEquipped() && m[opt_capture+1].value)
3214                                 *mode = NETGAME_HOARD;
3215                 else if (HoardEquipped() && m[opt_capture+2].value)
3216                                 *mode = NETGAME_TEAM_HOARD;
3217                 else if (anarchy_only) {
3218                         nm_messagebox(NULL, 1, TXT_OK, TXT_ANARCHY_ONLY_MISSION);
3219                         m[opt_mode+2].value = 0;
3220                         m[opt_mode+3].value = 0;
3221                         m[opt_mode].value = 1;
3222                         goto menu;
3223                 }               
3224                 else if ( m[opt_mode+2].value ) 
3225                         *mode = NETGAME_ROBOT_ANARCHY;
3226                 else if ( m[opt_mode+3].value ) 
3227                         *mode = NETGAME_COOPERATIVE;
3228                 else Int3(); // Invalid mode -- see Rob
3229 #endif
3230                 if (m[opt_closed].value)
3231                         Netgame.game_flags |= NETGAME_FLAG_CLOSED;
3232       
3233         }
3234
3235         return i;
3236 }
3237
3238 void
3239 network_set_game_mode(int gamemode)
3240 {
3241         Show_kill_list = 1;
3242
3243         if ( gamemode == NETGAME_ANARCHY )
3244                 Game_mode = GM_NETWORK;
3245         else if ( gamemode == NETGAME_ROBOT_ANARCHY )
3246                 Game_mode = GM_NETWORK | GM_MULTI_ROBOTS;
3247         else if ( gamemode == NETGAME_COOPERATIVE ) 
3248                 Game_mode = GM_NETWORK | GM_MULTI_COOP | GM_MULTI_ROBOTS;
3249         else if (gamemode == NETGAME_CAPTURE_FLAG)
3250                 {
3251                  Game_mode = GM_NETWORK | GM_TEAM | GM_CAPTURE;
3252                  Show_kill_list=3;
3253                 }
3254
3255         else if (HoardEquipped() && gamemode == NETGAME_HOARD)
3256                  Game_mode = GM_NETWORK | GM_HOARD;
3257         else if (HoardEquipped() && gamemode == NETGAME_TEAM_HOARD)
3258                  {
3259                   Game_mode = GM_NETWORK | GM_HOARD | GM_TEAM;
3260                   Show_kill_list=3;
3261                  }
3262         else if ( gamemode == NETGAME_TEAM_ANARCHY )
3263         {
3264                 Game_mode = GM_NETWORK | GM_TEAM;
3265                 Show_kill_list = 3;
3266         }
3267         else
3268                 Int3();
3269
3270 #if 0
3271 #ifdef MACINTOSH                        // minimize players on localtalk games
3272         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
3273                 if (Game_mode & GM_MULTI_ROBOTS)
3274                         MaxNumNetPlayers = 2;
3275                 else
3276                         MaxNumNetPlayers = 3;
3277         } else {
3278                 if (Game_mode & GM_MULTI_COOP)
3279                         MaxNumNetPlayers = 4;
3280                 else
3281                         MaxNumNetPlayers = 8;
3282         }
3283 #endif
3284 #endif
3285
3286 }
3287
3288 int
3289 network_find_game(void)
3290 {
3291         // Find out whether or not there is space left on this socket
3292
3293         fix t1;
3294
3295         Network_status = NETSTAT_BROWSING;
3296
3297         num_active_games = 0;
3298
3299         show_boxed_message(TXT_WAIT);
3300
3301         network_send_game_list_request();
3302         t1 = timer_get_approx_seconds() + F1_0*3;
3303
3304         while (timer_get_approx_seconds() < t1) // Wait 3 seconds for replies
3305                 network_listen();
3306
3307         clear_boxed_message();
3308
3309 //      mprintf((0, "%s %d %s\n", TXT_FOUND, num_active_games, TXT_ACTIVE_GAMES));
3310
3311         if (num_active_games < MAX_ACTIVE_NETGAMES)
3312                 return 0;
3313         return 1;
3314 }
3315         
3316 void network_read_sync_packet( netgame_info * sp, int rsinit)
3317 {       
3318 #ifdef MACINTOSH
3319         netgame_info tmp_info;
3320 #endif
3321
3322         int i, j;
3323         char temp_callsign[CALLSIGN_LEN+1];
3324
3325 #ifdef MACINTOSH
3326         if ( (Network_game_type == IPX_GAME) && (sp != &Netgame) ) {                            // for macintosh -- get the values unpacked to our structure format
3327                 receive_netgame_packet((ubyte *)sp, &tmp_info, 0);
3328                 sp = &tmp_info;
3329         }
3330 #endif
3331
3332    if (rsinit)
3333      TempPlayersInfo=&NetPlayers;
3334         
3335         // This function is now called by all people entering the netgame.
3336
3337         // mprintf( (0, "%s %d\n", TXT_STARTING_NETGAME, sp->levelnum ));
3338
3339         if (sp != &Netgame)
3340          {
3341           memcpy( &Netgame, sp, sizeof(netgame_info) );
3342           memcpy (&NetPlayers,TempPlayersInfo,sizeof (AllNetPlayers_info));
3343          }
3344
3345         N_players = sp->numplayers;
3346         Difficulty_level = sp->difficulty;
3347         Network_status = sp->game_status;
3348
3349    //Assert(Function_mode != FMODE_GAME);
3350
3351         // New code, 11/27
3352
3353         mprintf((1, "Netgame.checksum = %d, calculated checksum = %d.\n", Netgame.segments_checksum, my_segments_checksum));
3354
3355         if (Netgame.segments_checksum != my_segments_checksum)
3356         {
3357                 Network_status = NETSTAT_MENU;
3358                 nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NETLEVEL_NMATCH);
3359 #ifdef RELEASE
3360                 return;
3361 #endif
3362         }
3363
3364         // Discover my player number
3365
3366         memcpy(temp_callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
3367         
3368         Player_num = -1;
3369
3370         for (i=0; i<MAX_NUM_NET_PLAYERS; i++ )  {
3371                 Players[i].net_kills_total = 0;
3372 //              Players[i].net_killed_total = 0;
3373         }
3374
3375         for (i=0; i<N_players; i++ )    {
3376                 if (Network_game_type == IPX_GAME) {
3377                         if ( (!memcmp( TempPlayersInfo->players[i].network.ipx.node, My_Seq.player.network.ipx.node, 6 )) && (!stricmp( TempPlayersInfo->players[i].callsign, temp_callsign)) ) {
3378                                 if (Player_num!=-1) {
3379                                         Int3(); // Hey, we've found ourselves twice
3380                                         mprintf ((0,"Hey, we've found ourselves twice!\n"));
3381                                         Network_status = NETSTAT_MENU;
3382                                         return; 
3383                                 }
3384                                 change_playernum_to(i);
3385                         }
3386                 } else {
3387                         if ( (TempPlayersInfo->players[i].network.appletalk.node == My_Seq.player.network.appletalk.node) && (!stricmp( TempPlayersInfo->players[i].callsign, temp_callsign)) ) {
3388                                 if (Player_num!=-1) {
3389                                         Int3(); // Hey, we've found ourselves twice
3390                                         Network_status = NETSTAT_MENU;
3391                                         return; 
3392                                 }
3393                                 change_playernum_to(i);
3394                         }
3395                 }
3396                 memcpy( Players[i].callsign, TempPlayersInfo->players[i].callsign, CALLSIGN_LEN+1 );
3397
3398                 if (Network_game_type == IPX_GAME) {
3399                         if ( (*(uint *)TempPlayersInfo->players[i].network.ipx.server) != 0 )
3400                                 ipx_get_local_target( TempPlayersInfo->players[i].network.ipx.server, TempPlayersInfo->players[i].network.ipx.node, Players[i].net_address );
3401                         else
3402                                 memcpy( Players[i].net_address, TempPlayersInfo->players[i].network.ipx.node, 6 );
3403                 }
3404                                 
3405                 Players[i].n_packets_got=0;                             // How many packets we got from them
3406                 Players[i].n_packets_sent=0;                            // How many packets we sent to them
3407                 Players[i].connected = TempPlayersInfo->players[i].connected;
3408                 Players[i].net_kills_total = sp->player_kills[i];
3409                 Players[i].net_killed_total = sp->killed[i];
3410                 if ((Network_rejoined) || (i != Player_num))
3411                         Players[i].score = sp->player_score[i];
3412                 for (j = 0; j < MAX_NUM_NET_PLAYERS; j++)
3413                 {
3414                         kill_matrix[i][j] = sp->kills[i][j];
3415                 }
3416         }
3417
3418         if ( Player_num < 0 )   {
3419                 mprintf ((0,"Bad Player_num, resetting to NETSTAT_MENU!\n"));
3420                 Network_status = NETSTAT_MENU;
3421                 return;
3422         }
3423
3424         if (Network_rejoined) 
3425                 for (i=0; i<N_players;i++)
3426                         Players[i].net_killed_total = sp->killed[i];
3427
3428         if (Network_rejoined) {
3429                 network_process_monitor_vector(sp->monitor_vector);
3430                 Players[Player_num].time_level = sp->level_time;
3431         }
3432
3433         team_kills[0] = sp->team_kills[0];
3434         team_kills[1] = sp->team_kills[1];
3435         
3436         Players[Player_num].connected = 1;
3437    NetPlayers.players[Player_num].connected = 1;
3438    NetPlayers.players[Player_num].rank=GetMyNetRanking();
3439
3440         if (!Network_rejoined)
3441                 for (i=0; i<NumNetPlayerPositions; i++) {
3442                         Objects[Players[i].objnum].pos = Player_init[Netgame.locations[i]].pos;
3443                         Objects[Players[i].objnum].orient = Player_init[Netgame.locations[i]].orient;
3444                         obj_relink(Players[i].objnum,Player_init[Netgame.locations[i]].segnum);
3445                 }
3446
3447         Objects[Players[Player_num].objnum].type = OBJ_PLAYER;
3448
3449    mprintf ((0,"Changing to NETSTAT_PLAYING!\n"));
3450         Network_status = NETSTAT_PLAYING;
3451         Function_mode = FMODE_GAME;
3452         multi_sort_kill_list();
3453
3454 }
3455
3456 void
3457 network_send_sync(void)
3458 {
3459         int i, j, np;
3460
3461         // Randomize their starting locations...
3462
3463         d_srand( timer_get_fixed_seconds() );
3464         for (i=0; i<NumNetPlayerPositions; i++ )        
3465         {
3466                 if (Players[i].connected)
3467                         Players[i].connected = 1; // Get rid of endlevel connect statuses
3468                 if (Game_mode & GM_MULTI_COOP)
3469                         Netgame.locations[i] = i;
3470                 else {
3471                         do 
3472                         {
3473                                 np = d_rand() % NumNetPlayerPositions;
3474                                 for (j=0; j<i; j++ )    
3475                                 {
3476                                         if (Netgame.locations[j]==np)   
3477                                         {
3478                                                 np =-1;
3479                                                 break;
3480                                         }
3481                                 }
3482                         } while (np<0);
3483                         // np is a location that is not used anywhere else..
3484                         Netgame.locations[i]=np;
3485 //                      mprintf((0, "Player %d starting in location %d\n" ,i ,np ));
3486                 }
3487         }
3488
3489         // Push current data into the sync packet
3490
3491         network_update_netgame();
3492         Netgame.game_status = NETSTAT_PLAYING;
3493         Netgame.type = PID_SYNC;
3494         Netgame.segments_checksum = my_segments_checksum;
3495
3496         for (i=0; i<N_players; i++ )    {
3497                 if ((!Players[i].connected) || (i == Player_num))
3498                         continue;
3499
3500                 if (Network_game_type == IPX_GAME) {
3501                 // Send several times, extras will be ignored
3502                         #ifndef MACINTOSH
3503                         ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3504                         ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3505                         #else
3506                         send_netgame_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, NULL, 0);
3507                         send_netplayers_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3508                         #endif
3509                 #ifdef MACINTOSH
3510                 } else {
3511                                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), NetPlayers.players[i].network.appletalk.node,
3512                                         NetPlayers.players[i].network.appletalk.net,
3513                                         NetPlayers.players[i].network.appletalk.socket);
3514                                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), NetPlayers.players[i].network.appletalk.node,
3515                                         NetPlayers.players[i].network.appletalk.net,
3516                                         NetPlayers.players[i].network.appletalk.socket);
3517                 #endif
3518                 }
3519
3520         }       
3521         network_read_sync_packet(&Netgame,1); // Read it myself, as if I had sent it
3522 }
3523
3524 int
3525 network_select_teams(void)
3526 {
3527 #ifndef SHAREWARE
3528         newmenu_item m[MAX_PLAYERS+4];
3529         int choice, opt, opt_team_b;
3530         ubyte team_vector = 0;
3531         char team_names[2][CALLSIGN_LEN+1];
3532         int i;
3533         int pnums[MAX_PLAYERS+2];
3534
3535         // One-time initialization
3536
3537         for (i = N_players/2; i < N_players; i++) // Put first half of players on team A
3538         {
3539                 team_vector |= (1 << i);
3540         }
3541
3542         sprintf(team_names[0], "%s", TXT_BLUE);
3543         sprintf(team_names[1], "%s", TXT_RED);
3544
3545         // Here comes da menu
3546 menu:
3547         m[0].type = NM_TYPE_INPUT; m[0].text = team_names[0]; m[0].text_len = CALLSIGN_LEN; 
3548
3549         opt = 1;
3550         for (i = 0; i < N_players; i++)
3551         {
3552                 if (!(team_vector & (1 << i)))
3553                 {
3554                         m[opt].type = NM_TYPE_MENU; m[opt].text = NetPlayers.players[i].callsign; pnums[opt] = i; opt++;
3555                 }
3556         }
3557         opt_team_b = opt;
3558         m[opt].type = NM_TYPE_INPUT; m[opt].text = team_names[1]; m[opt].text_len = CALLSIGN_LEN; opt++;
3559         for (i = 0; i < N_players; i++)
3560         {
3561                 if (team_vector & (1 << i))
3562                 {
3563                         m[opt].type = NM_TYPE_MENU; m[opt].text = NetPlayers.players[i].callsign; pnums[opt] = i; opt++;
3564                 }
3565         }
3566         m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++;
3567         m[opt].type = NM_TYPE_MENU; m[opt].text = TXT_ACCEPT; opt++;
3568
3569         Assert(opt <= MAX_PLAYERS+4);
3570         
3571         choice = newmenu_do(NULL, TXT_TEAM_SELECTION, opt, m, NULL);
3572
3573         if (choice == opt-1)
3574         {
3575                 if ((opt-2-opt_team_b < 2) || (opt_team_b == 1)) 
3576                 {
3577                         nm_messagebox(NULL, 1, TXT_OK, TXT_TEAM_MUST_ONE);
3578                         #ifdef RELEASE
3579                                 goto menu;
3580                         #endif
3581                 }
3582                 
3583                 Netgame.team_vector = team_vector;
3584                 strcpy(Netgame.team_name[0], team_names[0]);
3585                 strcpy(Netgame.team_name[1], team_names[1]);
3586                 return 1;
3587         }
3588
3589         else if ((choice > 0) && (choice < opt_team_b)) {
3590                 team_vector |= (1 << pnums[choice]);
3591         }
3592         else if ((choice > opt_team_b) && (choice < opt-2)) {
3593                 team_vector &= ~(1 << pnums[choice]);
3594         }
3595         else if (choice == -1)
3596                 return 0;
3597         goto menu;
3598 #else
3599         return 0;
3600 #endif
3601 }
3602
3603 int
3604 network_select_players(void)
3605 {
3606         int i, j;
3607    newmenu_item m[MAX_PLAYERS+4];
3608    char text[MAX_PLAYERS+4][45];
3609         char title[50];
3610         int save_nplayers;              //how may people would like to join
3611
3612         network_add_player( &My_Seq );
3613                 
3614         for (i=0; i< MAX_PLAYERS+4; i++ ) {
3615                 sprintf( text[i], "%d.  %-20s", i+1, "" );
3616                 m[i].type = NM_TYPE_CHECK; m[i].text = text[i]; m[i].value = 0;
3617         }
3618
3619         m[0].value = 1;                         // Assume server will play...
3620
3621    if (FindArg("-norankings"))
3622                 sprintf( text[0], "%d. %-20s", 1, Players[Player_num].callsign );
3623         else
3624                 sprintf( text[0], "%d. %s%-20s", 1, RankStrings[NetPlayers.players[Player_num].rank],Players[Player_num].callsign );
3625
3626         sprintf( title, "%s %d %s", TXT_TEAM_SELECT, MaxNumNetPlayers, TXT_TEAM_PRESS_ENTER );
3627
3628 GetPlayersAgain:
3629    ExtGameStatus=GAMESTAT_NETGAME_PLAYER_SELECT;
3630         j=newmenu_do1( NULL, title, MAX_PLAYERS+4, m, network_start_poll, 1 );
3631
3632         save_nplayers = N_players;
3633
3634         if (j<0) 
3635         {
3636                 // Aborted!                                      
3637                 // Dump all players and go back to menu mode
3638
3639 abort:
3640                 for (i=1; i<save_nplayers; i++) {
3641                         if (Network_game_type == IPX_GAME)
3642                                 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, DUMP_ABORTED);
3643                         #ifdef MACINTOSH
3644                         else
3645                                 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, DUMP_ABORTED);
3646                         #endif
3647                 }
3648                         
3649
3650                 Netgame.numplayers = 0;
3651                 network_send_game_info(0); // Tell everyone we're bailing
3652
3653                 Network_status = NETSTAT_MENU;
3654                 return(0);
3655         }
3656        
3657         // Count number of players chosen
3658
3659         N_players = 0;
3660         for (i=0; i<save_nplayers; i++ )
3661         {
3662                 if (m[i].value) 
3663                         N_players++;
3664         }
3665         
3666         if ( N_players > Netgame.max_numplayers) {
3667                 #ifndef MACINTOSH
3668                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
3669                 #else
3670                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d netplayers for this game.", TXT_SORRY_ONLY, MaxNumNetPlayers );
3671                 #endif
3672                 N_players = save_nplayers;
3673                 goto GetPlayersAgain;
3674         }
3675
3676 #ifdef RELEASE
3677         if ( N_players < 2 )    {
3678                 nm_messagebox( TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_TWO );
3679                 N_players = save_nplayers;
3680                 goto GetPlayersAgain;
3681         }
3682 #endif
3683
3684 #ifdef RELEASE
3685         if ( (Netgame.gamemode == NETGAME_TEAM_ANARCHY ||
3686                    Netgame.gamemode == NETGAME_CAPTURE_FLAG || Netgame.gamemode == NETGAME_TEAM_HOARD) && (N_players < 2) ) {
3687                 nm_messagebox(TXT_ERROR, 1, TXT_OK, "You must select at least two\nplayers to start a team game" );
3688                 N_players = save_nplayers;
3689                 goto GetPlayersAgain;
3690         }
3691 #endif
3692
3693         // Remove players that aren't marked.
3694         N_players = 0;
3695         for (i=0; i<save_nplayers; i++ )        {
3696                 if (m[i].value) 
3697                 {
3698                         if (i > N_players)
3699                         {
3700                                 if (Network_game_type == IPX_GAME) {
3701                                         memcpy(NetPlayers.players[N_players].network.ipx.node, NetPlayers.players[i].network.ipx.node, 6);
3702                                         memcpy(NetPlayers.players[N_players].network.ipx.server, NetPlayers.players[i].network.ipx.server, 4);
3703                                 } else {
3704                                         NetPlayers.players[N_players].network.appletalk.node = NetPlayers.players[i].network.appletalk.node;
3705                                         NetPlayers.players[N_players].network.appletalk.net = NetPlayers.players[i].network.appletalk.net;
3706                                         NetPlayers.players[N_players].network.appletalk.socket = NetPlayers.players[i].network.appletalk.socket;
3707                                 }
3708                                 memcpy(NetPlayers.players[N_players].callsign, NetPlayers.players[i].callsign, CALLSIGN_LEN+1);
3709                                 NetPlayers.players[N_players].version_major=NetPlayers.players[i].version_major;
3710                                 NetPlayers.players[N_players].version_minor=NetPlayers.players[i].version_minor;
3711                                 NetPlayers.players[N_players].rank=NetPlayers.players[i].rank;
3712                                 ClipRank (&NetPlayers.players[N_players].rank);
3713                                 network_check_for_old_version(i);
3714                         }
3715                         Players[N_players].connected = 1;
3716                         N_players++;
3717                 }
3718                 else
3719                 {
3720                         if (Network_game_type == IPX_GAME)
3721                                 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, DUMP_DORK);
3722                         #ifdef MACINTOSH
3723                         else
3724                                 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, DUMP_DORK);
3725                         #endif
3726                 }
3727         }
3728
3729         for (i = N_players; i < MAX_NUM_NET_PLAYERS; i++) {
3730                 if (Network_game_type == IPX_GAME) {
3731                 memset(NetPlayers.players[i].network.ipx.node, 0, 6);
3732                 memset(NetPlayers.players[i].network.ipx.server, 0, 4);
3733             } else {
3734                 NetPlayers.players[i].network.appletalk.node = 0;
3735                 NetPlayers.players[i].network.appletalk.net = 0;
3736                 NetPlayers.players[i].network.appletalk.socket = 0;
3737             }
3738         memset(NetPlayers.players[i].callsign, 0, CALLSIGN_LEN+1);
3739                 NetPlayers.players[i].version_major=0;
3740                 NetPlayers.players[i].version_minor=0;
3741                 NetPlayers.players[i].rank=0;
3742         }
3743
3744    mprintf ((0,"Select teams: Game mode is %d\n",Netgame.gamemode));
3745
3746         if (Netgame.gamemode == NETGAME_TEAM_ANARCHY ||
3747             Netgame.gamemode == NETGAME_CAPTURE_FLAG ||
3748                  Netgame.gamemode == NETGAME_TEAM_HOARD)
3749                  if (!network_select_teams())
3750                         goto abort;
3751
3752         return(1); 
3753 }
3754
3755 void 
3756 network_start_game()
3757 {
3758         int i;
3759         char game_name[NETGAME_NAME_LEN+1];
3760         int chosen_game_mode, game_flags, level;
3761
3762         if (Network_game_type == IPX_GAME) {
3763
3764                 Assert( FRAME_INFO_SIZE < IPX_MAX_DATA_SIZE );
3765                 mprintf((0, "Using frame_info len %d, max %d.\n", FRAME_INFO_SIZE, IPX_MAX_DATA_SIZE));
3766                 
3767                 if ( !Network_active )
3768                 {
3769                         nm_messagebox(NULL, 1, TXT_OK, TXT_IPX_NOT_FOUND );
3770                         return;
3771                 }
3772         #ifdef MACINTOSH
3773         } else {
3774                 int err;
3775                 char buf[256];
3776
3777                 Assert( FRAME_INFO_SIZE < APPLETALK_MAX_DATA_SIZE );            
3778                 mprintf((0, "Using frame_info len %d, max %d.\n", sizeof(frame_info), APPLETALK_MAX_DATA_SIZE));
3779                 if (Appletalk_active <= 0) {
3780                         switch (Appletalk_active) {
3781                         case APPLETALK_NOT_OPEN:
3782                                 sprintf(buf, "Appletalk is not currently active.\nPlease enable AppleTalk from the\nChooser and restart Descent.");
3783                                 break;
3784                         case APPLETALK_BAD_LISTENER:
3785                                 sprintf(buf, "The Resource Fork of Descent appears damaged.\nPlease re-install Descent or contact\nMacPlay technical support.");
3786                                 break;
3787                         case APPLETALK_NO_LOCAL_ADDR:
3788                                 sprintf(buf, "Wow! Strange!\n\nNo Local Address.");
3789                                 break;
3790                         case APPLETALK_NO_SOCKET:
3791                                 sprintf(buf, "All AppleTalk sockets are in use.\nTry shutting down other network\napplications and restarting Descent.\n");
3792                                 break;
3793                         }
3794                         nm_messagebox(NULL, 1, TXT_OK, buf);
3795                         return;
3796                 }
3797                 strcpy(Network_zone_name, DEFAULT_ZONE_NAME);
3798         #endif
3799         }
3800
3801         network_init();
3802         change_playernum_to(0);
3803
3804         if (network_find_game())
3805         {
3806                 nm_messagebox(NULL, 1, TXT_OK, TXT_NET_FULL);
3807                 return;
3808         }
3809
3810         game_flags = 0;
3811         i = network_get_game_params( game_name, &chosen_game_mode, &game_flags, &level );
3812
3813         if (i<0) return;
3814
3815         N_players = 0;
3816
3817 // LoadLevel(level); Old, no longer used.
3818
3819         Netgame.difficulty = Difficulty_level;
3820         Netgame.gamemode = chosen_game_mode;
3821         Netgame.game_status = NETSTAT_STARTING;
3822         Netgame.numplayers = 0;
3823         Netgame.max_numplayers = MaxNumNetPlayers;
3824         Netgame.levelnum = level;
3825         Netgame.protocol_version = MULTI_PROTO_VERSION;
3826
3827         strcpy(Netgame.game_name, game_name);
3828         
3829         Network_status = NETSTAT_STARTING;
3830
3831         #ifdef MACINTOSH
3832         if (Network_game_type == APPLETALK_GAME) {
3833                 OSErr err;
3834                 fix t1;
3835                 int count = 0;
3836                 
3837                 show_boxed_message("Registering Netgame");
3838                 do {
3839                         err = appletalk_register_netgame( game_name, TickCount() );
3840                         t1 = timer_get_fixed_seconds() + F1_0;
3841                         while (timer_get_fixed_seconds() < t1) ;
3842                         count++;
3843                 } while ( (err == nbpDuplicate) && (count != MAX_REGISTER_TRIES) );
3844                 clear_boxed_message();
3845                 if ( (err == tooManyReqs) || (count == MAX_REGISTER_TRIES) ) {
3846                         nm_messagebox(NULL, 1, TXT_OK, "AppleTalk Network is too busy.\nPlease try again shortly.");
3847                         Game_mode = GM_GAME_OVER;
3848                         return;
3849                 }
3850         }
3851         #endif
3852
3853         network_set_game_mode(Netgame.gamemode);
3854
3855    d_srand( timer_get_fixed_seconds() );
3856    Netgame.Security=d_rand();  // For syncing Netgames with player packets
3857
3858         if(network_select_players())
3859         {
3860                 StartNewLevel(Netgame.levelnum, 0);
3861         }
3862         else
3863                 Game_mode = GM_GAME_OVER;
3864         
3865 }
3866
3867 void restart_net_searching(newmenu_item * m)
3868 {
3869         int i;
3870         N_players = 0;
3871         num_active_games = 0;
3872
3873         memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
3874
3875         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++)
3876         {
3877                 sprintf(m[i+2].text, "%d.                                                     ",i+1);
3878                 m[i+2].redraw = 1;
3879         }
3880