]> icculus.org git repositories - btb/d2x.git/blob - main/network.c
This commit was generated by cvs2svn to compensate for changes in r5,
[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.1.1.2 2001-01-19 03:33:46 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 #define LHX(x)          ((x)*(MenuHires?2:1))
76 #define LHY(y)          ((y)*(MenuHires?2.4:1))
77
78 #define PID_LITE_INFO                           43
79 #define PID_SEND_ALL_GAMEINFO      44
80 #define PID_PLAYERSINFO                         45
81 #define PID_REQUEST                                     46
82 #define PID_SYNC                                                47
83 #define PID_PDATA                                               48
84 #define PID_ADDPLAYER                           49
85 #define PID_DUMP                                                51
86 #define PID_ENDLEVEL                                    52
87 #define PID_QUIT_JOINING                        54
88 #define PID_OBJECT_DATA                         55
89 #define PID_GAME_LIST                           56
90 #define PID_GAME_INFO                           57
91 #define PID_PING_SEND                           58
92 #define PID_PING_RETURN                         59
93 #define PID_GAME_UPDATE                         60
94 #define PID_ENDLEVEL_SHORT                      61
95 #define PID_NAKED_PDATA                         62
96 #define PID_GAME_PLAYERS                                                                63
97 #define PID_NAMES_RETURN                                                                64
98
99 #define NETGAME_ANARCHY                         0
100 #define NETGAME_TEAM_ANARCHY            1
101 #define NETGAME_ROBOT_ANARCHY           2
102 #define NETGAME_COOPERATIVE             3
103 #define NETGAME_CAPTURE_FLAG            4
104 #define NETGAME_HOARD                            5
105 #define NETGAME_TEAM_HOARD                                       6
106
107 #define NETSECURITY_OFF 0
108 #define NETSECURITY_WAIT_FOR_PLAYERS 1
109 #define NETSECURITY_WAIT_FOR_GAMEINFO 2
110 #define NETSECURITY_WAIT_FOR_SYNC 3
111
112 // MWA -- these structures are aligned -- please save me sanity and
113 // headaches by keeping alignment if these are changed!!!!  Contact
114 // me for info.
115
116 typedef struct endlevel_info {
117         ubyte                                   type;
118         ubyte                                   player_num;
119         byte                                    connected;
120         ubyte                                   seconds_left;
121         short                                   kill_matrix[MAX_PLAYERS][MAX_PLAYERS];
122         short                                   kills;
123         short                                   killed;
124 } endlevel_info;
125
126 typedef struct endlevel_info_short {
127         ubyte                                   type;
128         ubyte                                   player_num;
129         byte                                    connected;
130         ubyte                                   seconds_left;
131 } endlevel_info_short;
132
133 // WARNING!!! This is the top part of netgame_info...if that struct changes,
134 //      this struct much change as well.  ie...they are aligned and the join system will
135 // not work without it.
136
137 // MWA  if this structure changes -- please make appropriate changes to receive_netgame_info
138 // code for macintosh in netmisc.c
139
140 typedef struct lite_info {
141         ubyte                           type;
142         int                             Security;
143         char                            game_name[NETGAME_NAME_LEN+1];
144         char                            mission_title[MISSION_NAME_LEN+1];
145         char                            mission_name[9];
146         int                             levelnum;
147         ubyte                           gamemode;
148         ubyte                           RefusePlayers;
149         ubyte                           difficulty;
150         ubyte                           game_status;
151         ubyte                           numplayers;
152         ubyte                           max_numplayers;
153         ubyte                           numconnected;
154         ubyte                           game_flags;
155         ubyte                           protocol_version;
156         ubyte                           version_major;
157         ubyte                           version_minor;
158         ubyte                           team_vector;
159  } lite_info;
160
161 // IF YOU CHANGE THE SIZE OF ANY OF THE FOLLOWING STRUCTURES
162 // MAKE THE MACINTOSH DEFINES BE THE SAME SIZE AS THE PC OR
163 // I WILL HAVE TO HURT YOU VERY BADLY!!!  -- MWA
164
165 #ifdef MACINTOSH
166 #define NETGAME_INFO_SIZE               ( Network_game_type == IPX_GAME?355:sizeof(netgame_info) )
167 #define ALLNETPLAYERSINFO_SIZE  ( Network_game_type == IPX_GAME?317:sizeof(AllNetPlayers_info) )
168 #define LITE_INFO_SIZE                  ( Network_game_type == IPX_GAME?72:sizeof(lite_info) )
169 #define SEQUENCE_PACKET_SIZE    ( Network_game_type == IPX_GAME?34:sizeof(sequence_packet) )
170 #define FRAME_INFO_SIZE                 ( Network_game_type == IPX_GAME?541:sizeof(frame_info) )
171 #define IPX_SHORT_INFO_SIZE             ( 490 )
172 #else
173 #define NETGAME_INFO_SIZE               sizeof(netgame_info)
174 #define ALLNETPLAYERSINFO_SIZE  sizeof(AllNetPlayers_info)
175 #define LITE_INFO_SIZE                  sizeof(lite_info)
176 #define SEQUENCE_PACKET_SIZE    sizeof(sequence_packet)
177 #define FRAME_INFO_SIZE                 sizeof(frame_info)
178 #endif
179
180 #define MAX_ACTIVE_NETGAMES     12
181
182 netgame_info Active_games[MAX_ACTIVE_NETGAMES];
183 AllNetPlayers_info ActiveNetPlayers[MAX_ACTIVE_NETGAMES];
184 AllNetPlayers_info *TempPlayersInfo,TempPlayersBase;
185 int NamesInfoSecurity=-1;
186
187 // MWAnetgame_info *TempNetInfo; 
188 netgame_info TempNetInfo;
189
190 extern void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[]);
191 extern void multi_send_kill_goal_counts();
192 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) );
193
194 void network_process_naked_pdata (char *,int);
195 extern void multi_send_robot_controls(char);
196
197 int num_active_games = 0;
198 int PacketsPerSec=10;
199 int MaxXDataSize=NET_XDATA_SIZE;
200
201 int       Netlife_kills=0, Netlife_killed=0;
202
203 int     Network_debug=0;
204 int     Network_active=0;
205
206 int     Network_status = 0;
207 int     Network_games_changed = 0;
208
209 int     Network_socket = 0;
210 int     Network_allow_socket_changes = 1;
211
212 int     NetSecurityFlag=NETSECURITY_OFF;
213 int     NetSecurityNum=0;
214 int       Network_sending_extras=0;
215 int      VerifyPlayerJoined=-1;
216 int       Player_joining_extras=-1;  // This is so we know who to send 'latecomer' packets to.
217                                                                                           // We could just send updates to everyone but that kills the sender!   
218
219 // For rejoin object syncing
220
221 int     Network_rejoined = 0;       // Did WE rejoin this game?
222 int     Network_new_game = 0;            // Is this the first level of a new game?
223 int     Network_send_objects = 0;  // Are we in the process of sending objects to a player?
224 int     Network_send_objnum = -1;   // What object are we sending next?
225 int     Network_player_added = 0;   // Is this a new player or a returning player?
226 int     Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic?
227 sequence_packet Network_player_rejoining; // Who is rejoining now?
228
229 fix     LastPacketTime[MAX_PLAYERS]; // For timeouts of idle/crashed players
230
231 int     PacketUrgent = 0;
232 int   NetGameType=0;
233 int     TotalMissedPackets=0,TotalPacketsGot=0;
234
235 frame_info      MySyncPack,UrgentSyncPack;
236 ubyte           MySyncPackInitialized = 0;              // Set to 1 if the MySyncPack is zeroed.
237 ushort          my_segments_checksum = 0;
238
239 sequence_packet My_Seq;
240 char WantPlayersInfo=0;
241 char WaitingForPlayerInfo=0;
242
243 char *RankStrings[]={"(unpatched) ","Cadet ","Ensign ","Lieutenant ","Lt.Commander ",
244                                                                 "Commander ","Captain ","Vice Admiral ","Admiral ","Demigod "};
245
246 extern obj_position Player_init[MAX_PLAYERS];
247
248 extern int force_cockpit_redraw;
249
250 #define DUMP_CLOSED 0
251 #define DUMP_FULL 1
252 #define DUMP_ENDLEVEL 2
253 #define DUMP_DORK 3
254 #define DUMP_ABORTED 4
255 #define DUMP_CONNECTED 5
256 #define DUMP_LEVEL 6
257 #define DUMP_KICKED 7
258
259 extern ubyte Version_major,Version_minor;
260 extern ubyte SurfingNet;
261 extern char MaxPowerupsAllowed[MAX_POWERUP_TYPES];
262 extern char PowerupsInMine[MAX_POWERUP_TYPES];
263
264 extern void multi_send_stolen_items();
265
266 int network_wait_for_snyc();
267 extern void multi_send_wall_status (int,ubyte,ubyte,ubyte);
268 extern void multi_send_wall_status_specific (int,int,ubyte,ubyte,ubyte);
269
270 extern void game_disable_cheats();
271
272 char IWasKicked=0;
273 FILE *SendLogFile,*RecieveLogFile;
274 int TTSent[100],TTRecv[100];
275
276 extern int Final_boss_is_dead;
277
278 // following is network stuff for appletalk
279
280 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
281
282 #define NETWORK_OEM 0x10
283
284 #ifdef MACINTOSH
285
286 int Network_game_type;                                  // used to tell IPX vs. appletalk games
287
288 #define MAX_ZONES                       255
289 #define MAX_ZONE_LENGTH         33
290 #define DEFAULT_ZONE_NAME       "\p*"
291 #define MAX_REGISTER_TRIES      5                                       // maximum time we will try and register a netgame
292 char Network_zone_name[MAX_ZONE_LENGTH];                // zone name game being played in for appletalk
293 char Zone_names[MAX_ZONES][MAX_ZONE_LENGTH];    // total list of zones that we can see
294 ubyte appletalk_use_broadcast = 0;
295 ubyte Network_game_validated = 0;               // validates a game before being able to join
296 ubyte Network_game_validate_choice = 0;
297 ubyte Network_appletalk_type = 0;               // type of appletalk network game is being played on
298
299 #define ETHERTALK_TYPE  0
300 #define LOCALTALK_TYPE  1
301 #define OTHERTALK_TYPE  2
302
303
304 void network_release_registered_game(void);
305
306 #endif
307
308 void
309 network_init(void)
310 {
311   
312         // So you want to play a netgame, eh?  Let's a get a few things
313         // straight
314
315    int t;
316         int save_pnum = Player_num;
317
318         game_disable_cheats();
319    IWasKicked=0;
320    Final_boss_is_dead=0;
321    NamesInfoSecurity=-1;
322
323
324    #ifdef NETPROFILING
325            OpenSendLog();
326                 OpenRecieveLog(); 
327         #endif
328         
329         for (t=0;t<MAX_POWERUP_TYPES;t++)
330                 {
331                         MaxPowerupsAllowed[t]=0;
332                         PowerupsInMine[t]=0;
333                 }
334
335    TotalMissedPackets=0; TotalPacketsGot=0;
336
337         memset(&Netgame, 0, sizeof(netgame_info));
338         memset(&NetPlayers,0,sizeof(AllNetPlayers_info));
339         memset(&My_Seq, 0, sizeof(sequence_packet));
340         My_Seq.type = PID_REQUEST;
341         memcpy(My_Seq.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
342
343    #if defined (D2_OEM)
344            Version_minor|=NETWORK_OEM;
345         #endif
346  
347         My_Seq.player.version_major=Version_major;
348         My_Seq.player.version_minor=Version_minor;
349    My_Seq.player.rank=GetMyNetRanking();        
350  
351         if (Network_game_type == IPX_GAME) {
352                 memcpy(My_Seq.player.network.ipx.node, ipx_get_my_local_address(), 6);
353                 memcpy(My_Seq.player.network.ipx.server, ipx_get_my_server_address(), 4 );
354         #ifdef MACINTOSH
355         } else {
356                 My_Seq.player.network.appletalk.node = appletalk_get_my_node();
357                 My_Seq.player.network.appletalk.net = appletalk_get_my_net();
358                 My_Seq.player.network.appletalk.socket = appletalk_get_my_socket();
359         #endif
360         }
361 #ifdef MACINTOSH
362         My_Seq.player.computer_type = MAC;
363 #else
364         My_Seq.player.computer_type = DOS;
365 #endif
366
367         for (Player_num = 0; Player_num < MAX_NUM_NET_PLAYERS; Player_num++)
368                 init_player_stats_game();
369
370         Player_num = save_pnum;         
371         multi_new_game();
372         Network_new_game = 1;
373         Control_center_destroyed = 0;
374         network_flush();
375
376         Netgame.PacketsPerSec=10;
377
378    if ((t=args_find("-packets")))
379     {
380      Netgame.PacketsPerSec=atoi(Args[t+1]);
381      if (Netgame.PacketsPerSec<1)
382       Netgame.PacketsPerSec=1;
383      else if (Netgame.PacketsPerSec>20)
384       Netgame.PacketsPerSec=20;
385      mprintf ((0,"Will send %d packets per second",Netgame.PacketsPerSec));
386     }
387    if (args_find("-shortpackets"))
388     {
389      Netgame.ShortPackets=1;
390      mprintf ((0,"Will send short packets.\n"));
391     }
392 }
393
394 int
395 network_i_am_master(void)
396 {
397         // I am the lowest numbered player in this game?
398
399         int i;
400
401         if (!(Game_mode & GM_NETWORK))
402                 return (Player_num == 0);
403
404         for (i = 0; i < Player_num; i++)
405                 if (Players[i].connected)
406                         return 0;
407         return 1;
408 }
409 int
410 network_who_is_master(void)
411 {
412         // Who is the master of this game?
413
414         int i;
415
416         if (!(Game_mode & GM_NETWORK))
417                 return (Player_num == 0);
418
419         for (i = 0; i < N_players; i++)
420                 if (Players[i].connected)
421                         return i;
422         return Player_num;
423 }
424 int network_how_many_connected()
425  {
426   int num=0,i;
427  
428         for (i = 0; i < N_players; i++)
429                 if (Players[i].connected)
430                         num++;
431    return (num);
432  }
433
434 #define ENDLEVEL_SEND_INTERVAL (F1_0*2)
435 #define ENDLEVEL_IDLE_TIME      (F1_0*20)
436 /*      
437 void 
438 network_endlevel_poll( int nitems, newmenu_item * menus, int * key, int citem )
439 {
440         // Polling loop for End-of-level menu
441
442         static fix t1 = 0;
443         int i = 0;
444         int num_ready = 0;
445         int num_escaped = 0;
446         int goto_secret = 0;
447
448         int previous_state[MAX_NUM_NET_PLAYERS];
449         int previous_seconds_left;
450
451         menus = menus;
452         citem = citem;
453         nitems = nitems;
454         key = key;
455
456         // Send our endlevel packet at regular intervals
457
458         if (timer_get_approx_seconds() > (t1+ENDLEVEL_SEND_INTERVAL))
459         {
460                 network_send_endlevel_packet();
461                 t1 = timer_get_approx_seconds();
462         }
463
464         for (i = 0; i < N_players; i++)
465                 previous_state[i] = Players[i].connected;
466
467         previous_seconds_left = Countdown_seconds_left;
468
469         network_listen();
470
471         for (i = 0; i < N_players; i++)
472         {
473                 if (Players[i].connected == 1)
474                 {
475                         // Check timeout for idle players
476                         if (timer_get_approx_seconds() > LastPacketTime[i]+ENDLEVEL_IDLE_TIME)
477                         {
478                                 mprintf((0, "idle timeout for player %d.\n", i));
479                                 Players[i].connected = 0;
480                                 network_send_endlevel_sub(i);
481                         }                               
482                 }
483
484                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
485                         num_ready++;
486                 if (Players[i].connected != 1)
487                         num_escaped++;
488                 if (Players[i].connected == 4)
489                         goto_secret = 1;
490         }
491
492         if (num_escaped == N_players) // All players are out of the mine
493         {
494                 Countdown_seconds_left = -1;
495         }
496
497
498         if (num_ready == N_players) // All players have checked in or are disconnected
499         {
500                 if (goto_secret)
501                         *key = -3;
502                 else
503                         *key = -2;
504         }
505 } */
506   
507 void 
508 network_endlevel_poll2( int nitems, newmenu_item * menus, int * key, int citem )
509 {
510         // Polling loop for End-of-level menu
511
512         static fix t1 = 0;
513         int i = 0;
514         int num_ready = 0;
515         int goto_secret = 0;
516
517         menus = menus;
518         citem = citem;
519         nitems = nitems;
520         key = key;
521
522         // Send our endlevel packet at regular intervals
523
524         if (timer_get_approx_seconds() > (t1+ENDLEVEL_SEND_INTERVAL))
525         {
526                 network_send_endlevel_packet();
527                 t1 = timer_get_approx_seconds();
528         }
529
530 //   mprintf ((0,"Trying to listen!\n"));
531         network_listen();
532
533         for (i = 0; i < N_players; i++)
534         {
535                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
536                         num_ready++;
537                 if (Players[i].connected == 4)
538                         goto_secret = 1;                                        
539         }
540
541         if (num_ready == N_players) // All players have checked in or are disconnected
542         {
543                 if (goto_secret)
544                         *key = -3;
545                 else
546                         *key = -2;
547         }
548 }
549
550
551 extern fix StartAbortMenuTime;
552
553 void 
554 network_endlevel_poll3( int nitems, newmenu_item * menus, int * key, int citem )
555 {
556         // Polling loop for End-of-level menu
557
558    int num_ready=0,i;
559  
560         menus = menus;
561         citem = citem;
562         nitems = nitems;
563         key = key;
564
565         if (timer_get_approx_seconds() > (StartAbortMenuTime+(F1_0 * 8)))
566     *key=-2;
567
568
569         network_listen();
570
571
572         for (i = 0; i < N_players; i++)
573                 if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
574                         num_ready++;
575
576         if (num_ready == N_players) // All players have checked in or are disconnected
577                         *key = -2;
578
579 }
580
581
582 int
583 network_endlevel(int *secret)
584 {
585         // Do whatever needs to be done between levels
586
587    int i;
588
589    *secret=0;
590
591         //network_flush();
592
593         Network_status = NETSTAT_ENDLEVEL; // We are between levels
594
595         network_listen();
596
597         network_send_endlevel_packet();
598
599         for (i=0; i<N_players; i++) 
600         {
601                 LastPacketTime[i] = timer_get_approx_seconds();
602         }
603    
604         network_send_endlevel_packet();
605         network_send_endlevel_packet();
606         MySyncPackInitialized = 0;
607
608         network_update_netgame();
609
610         return(0);
611 }
612
613 int 
614 can_join_netgame(netgame_info *game,AllNetPlayers_info *people)
615 {
616         // Can this player rejoin a netgame in progress?
617
618         int i, num_players;
619
620         if (game->game_status == NETSTAT_STARTING)
621      return 1;
622
623         if (game->game_status != NETSTAT_PLAYING)
624     {
625       mprintf ((0,"Error: Can't join because game_status !=NETSTAT_PLAYING\n"));
626                 return 0;
627     }
628
629    if (game->version_major==0 && Version_major>0)
630     {
631            mprintf ((0,"Error:Can't join because version majors don't match!\n"));
632                 return (0);
633     }
634
635         if (game->version_major>0 && Version_major==0)
636     {
637            mprintf ((0,"Error:Can't join because version majors2 don't match!\n"));
638                 return (0);
639     }
640
641         // Game is in progress, figure out if this guy can re-join it
642
643         num_players = game->numplayers;
644
645         if (!(game->game_flags & NETGAME_FLAG_CLOSED)) {
646                 // Look for player that is not connected
647                 
648                 if (game->numconnected==game->max_numplayers)
649                  return (2);
650
651 //      mprintf ((0,"Refuse = %d\n",game->RefusePlayers));
652                 
653                 if (game->RefusePlayers)
654                  return (3);
655                 
656                 if (game->numplayers < game->max_numplayers)
657                         return 1;
658
659                 if (game->numconnected<num_players)
660                         return 1;
661                      
662         }
663
664         if (people==NULL)
665     {
666       mprintf ((0,"Error! Can't join because people==NULL!\n"));
667                 return 0;
668     }
669         
670         // Search to see if we were already in this closed netgame in progress
671
672         for (i = 0; i < num_players; i++) {
673                 if (Network_game_type == IPX_GAME) {
674                         if ( (!stricmp(Players[Player_num].callsign, people->players[i].callsign)) &&
675                                   (!memcmp(My_Seq.player.network.ipx.node, people->players[i].network.ipx.node, 6)) &&
676                                   (!memcmp(My_Seq.player.network.ipx.server, people->players[i].network.ipx.server, 4)) )
677                                 break;
678                 } else {
679                         if ( (!stricmp(Players[Player_num].callsign, people->players[i].callsign)) &&
680                                   (My_Seq.player.network.appletalk.node == people->players[i].network.appletalk.node) &&
681                                   (My_Seq.player.network.appletalk.net == people->players[i].network.appletalk.net) )
682                                 break;
683                 }
684         }
685
686         if (i != num_players)
687                 return 1;
688  
689    mprintf ((0,"Error: Can't join because at end of list!\n"));
690         return 0;
691 }
692
693 void
694 network_disconnect_player(int playernum)
695 {
696         // A player has disconnected from the net game, take whatever steps are
697         // necessary 
698
699         if (playernum == Player_num) 
700         {
701                 Int3(); // Weird, see Rob
702                 return;
703         }
704
705         Players[playernum].connected = 0;
706    NetPlayers.players[playernum].connected = 0;
707    if (VerifyPlayerJoined==playernum)
708           VerifyPlayerJoined=-1;
709
710 //      create_player_appearance_effect(&Objects[Players[playernum].objnum]);
711         multi_make_player_ghost(playernum);
712
713         if (Newdemo_state == ND_STATE_RECORDING)
714                 newdemo_record_multi_disconnect(playernum);
715
716         multi_strip_robots(playernum);
717 }
718                 
719 void
720 network_new_player(sequence_packet *their)
721 {
722         int objnum;
723         int pnum;
724
725         pnum = their->player.connected;
726
727         Assert(pnum >= 0);
728         Assert(pnum < MaxNumNetPlayers);        
729         
730         objnum = Players[pnum].objnum;
731
732         if (Newdemo_state == ND_STATE_RECORDING) {
733                 int new_player;
734
735                 if (pnum == N_players)
736                         new_player = 1;
737                 else
738                         new_player = 0;
739                 newdemo_record_multi_connect(pnum, new_player, their->player.callsign);
740         }
741
742         memcpy(Players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
743         memcpy(NetPlayers.players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
744         
745
746    ClipRank (&their->player.rank);
747    NetPlayers.players[pnum].rank=their->player.rank;
748         NetPlayers.players[pnum].version_major=their->player.version_major;
749         NetPlayers.players[pnum].version_minor=their->player.version_minor;
750    network_check_for_old_version(pnum);
751
752         if (Network_game_type == IPX_GAME) {
753                 if ( (*(uint *)their->player.network.ipx.server) != 0 )
754                         ipx_get_local_target( their->player.network.ipx.server, their->player.network.ipx.node, Players[pnum].net_address );
755                 else
756                         memcpy(Players[pnum].net_address, their->player.network.ipx.node, 6);
757         
758                 memcpy(NetPlayers.players[pnum].network.ipx.node, their->player.network.ipx.node, 6);
759                 memcpy(NetPlayers.players[pnum].network.ipx.server, their->player.network.ipx.server, 4);
760         } else {
761                 NetPlayers.players[pnum].network.appletalk.node = their->player.network.appletalk.node;
762                 NetPlayers.players[pnum].network.appletalk.net = their->player.network.appletalk.net;
763                 NetPlayers.players[pnum].network.appletalk.socket = their->player.network.appletalk.socket;
764         }
765
766         Players[pnum].n_packets_got = 0;
767         Players[pnum].connected = 1;
768         Players[pnum].net_kills_total = 0;
769         Players[pnum].net_killed_total = 0;
770         memset(kill_matrix[pnum], 0, MAX_PLAYERS*sizeof(short)); 
771         Players[pnum].score = 0;
772         Players[pnum].flags = 0;
773         Players[pnum].KillGoalCount=0;
774
775         if (pnum == N_players)
776         {
777                 N_players++;
778                 Netgame.numplayers = N_players;
779         }
780
781         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
782
783    ClipRank (&their->player.rank);
784    
785    if (args_find("-norankings"))
786           HUD_init_message("'%s' %s\n",their->player.callsign, TXT_JOINING);
787    else   
788      HUD_init_message("%s'%s' %s\n",RankStrings[their->player.rank],their->player.callsign, TXT_JOINING);
789         
790         multi_make_ghost_player(pnum);
791
792         multi_send_score();
793         multi_sort_kill_list();
794
795 //      create_player_appearance_effect(&Objects[objnum]);
796 }
797
798 char RefuseThisPlayer=0,WaitForRefuseAnswer=0,RefuseTeam;
799 char RefusePlayerName[12];
800 fix RefuseTimeLimit=0;
801
802 void network_welcome_player(sequence_packet *their)
803 {
804         // Add a player to a game already in progress
805         ubyte local_address[6];
806         int player_num;
807         int i;
808
809    WaitForRefuseAnswer=0;
810
811         if (args_find("-NoMatrixCheat"))
812         {
813                 if (their->player.version_minor & 0x0F<3)
814                 {
815                                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_DORK);
816                                         return;
817                 }
818         }
819
820         if (HoardEquipped())
821         {
822    // If hoard game, and this guy isn't D2 Christmas (v1.2), dump him
823
824            if ((Game_mode & GM_HOARD) && ((their->player.version_minor & 0x0F)<2))
825                 {
826                         if (Network_game_type == IPX_GAME)
827                                 network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_DORK);
828                         #ifdef MACINTOSH
829                         else
830                                 network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_DORK);
831                         #endif
832                         return;
833                 }
834         }
835
836         // Don't accept new players if we're ending this level.  Its safe to
837         // ignore since they'll request again later
838
839         if ((Endlevel_sequence) || (Control_center_destroyed))
840         {
841                 mprintf((0, "Ignored request from new player to join during endgame.\n"));
842                 if (Network_game_type == IPX_GAME)
843                         network_dump_player(their->player.network.ipx.server,their->player.network.ipx.node, DUMP_ENDLEVEL);
844                 #ifdef MACINTOSH
845                 else
846                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_ENDLEVEL);
847                 #endif
848                 return; 
849         }
850
851         if (Network_send_objects || Network_sending_extras)
852         {
853                 // Ignore silently, we're already responding to someone and we can't
854                 // do more than one person at a time.  If we don't dump them they will
855                 // re-request in a few seconds.
856                 return;
857         }
858
859         if (their->player.connected != Current_level_num)
860         {
861                 mprintf((0, "Dumping player due to old level number.\n"));
862                 if (Network_game_type == IPX_GAME)
863                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_LEVEL);
864                 #ifdef MACINTOSH
865                 else
866                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_LEVEL);
867                 #endif
868                 return;
869         }
870
871         player_num = -1;
872         memset(&Network_player_rejoining, 0, sizeof(sequence_packet));
873         Network_player_added = 0;
874
875         if (Network_game_type == IPX_GAME) {
876                 if ( (*(uint *)their->player.network.ipx.server) != 0 )
877                         ipx_get_local_target( their->player.network.ipx.server, their->player.network.ipx.node, local_address );
878                 else
879                         memcpy(local_address, their->player.network.ipx.node, 6);
880         }
881
882         for (i = 0; i < N_players; i++)
883         {
884                 if ( (Network_game_type == IPX_GAME) && (!stricmp(Players[i].callsign, their->player.callsign )) && (!memcmp(Players[i].net_address,local_address, 6)) ) 
885                 {
886                         player_num = i;
887                         break;
888                 }
889 #ifdef MACINTOSH                // note link to above if
890                         else if ( (!stricmp(Players[i].callsign, their->player.callsign)) &&
891                                     (NetPlayers.players[i].network.appletalk.node == their->player.network.appletalk.node) &&
892                                         (NetPlayers.players[i].network.appletalk.net == their->player.network.appletalk.net)) {
893                         player_num = i;
894                         break;
895                 }
896 #endif
897         }
898
899         if (player_num == -1)
900         {
901                 // Player is new to this game
902
903                 if ( !(Netgame.game_flags & NETGAME_FLAG_CLOSED) && (N_players < MaxNumNetPlayers))
904                 {
905                         // Add player in an open slot, game not full yet
906
907                         player_num = N_players;
908                         Network_player_added = 1;
909                 }
910                 else if (Netgame.game_flags & NETGAME_FLAG_CLOSED)
911                 {
912                         // Slots are open but game is closed
913
914                         if (Network_game_type == IPX_GAME)
915                                 network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_CLOSED);
916                         #ifdef MACINTOSH
917                         else
918                                 network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_CLOSED);
919                         #endif
920                         return;
921                 }
922                 else
923                 {
924                         // Slots are full but game is open, see if anyone is
925                         // disconnected and replace the oldest player with this new one
926                 
927                         int oldest_player = -1;
928                         fix oldest_time = timer_get_approx_seconds();
929
930                         Assert(N_players == MaxNumNetPlayers);
931
932                         for (i = 0; i < N_players; i++)
933                         {
934                                 if ( (!Players[i].connected) && (LastPacketTime[i] < oldest_time))
935                                 {
936                                         oldest_time = LastPacketTime[i];
937                                         oldest_player = i;
938                                 }
939                         }
940
941                         if (oldest_player == -1)
942                         {
943                                 // Everyone is still connected 
944
945                                 if (Network_game_type == IPX_GAME)
946                                         network_dump_player(their->player.network.ipx.server, their->player.network.ipx.node, DUMP_FULL);
947                                 #ifdef MACINTOSH
948                                 else
949                                         network_dump_appletalk_player(their->player.network.appletalk.node, their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_FULL);
950                                 #endif
951                                 return;
952                         }
953                         else
954                         {       
955                                 // Found a slot!
956
957                                 player_num = oldest_player;
958                                 Network_player_added = 1;
959                         }
960                 }
961         }
962         else 
963         {
964                 // Player is reconnecting
965                 
966                 if (Players[player_num].connected)
967                 {
968                         mprintf((0, "Extra REQUEST from player ignored.\n"));
969                         return;
970                 }
971
972                 if (Newdemo_state == ND_STATE_RECORDING)
973                         newdemo_record_multi_reconnect(player_num);
974
975                 Network_player_added = 0;
976
977                 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
978                 
979                 if (args_find("-norankings"))
980                         HUD_init_message("'%s' %s", Players[player_num].callsign, TXT_REJOIN);
981                 else
982                         HUD_init_message("%s'%s' %s", RankStrings[NetPlayers.players[player_num].rank],Players[player_num].callsign, TXT_REJOIN);
983         }
984
985         Players[player_num].KillGoalCount=0;
986
987         // Send updated Objects data to the new/returning player
988
989         
990         Network_player_rejoining = *their;
991         Network_player_rejoining.player.connected = player_num;
992         Network_send_objects = 1;
993         Network_send_objnum = -1;
994
995         network_send_objects();
996 }
997
998 int network_objnum_is_past(int objnum)
999 {
1000         // determine whether or not a given object number has already been sent
1001         // to a re-joining player.
1002         
1003         int player_num = Network_player_rejoining.player.connected;
1004         int obj_mode = !((object_owner[objnum] == -1) || (object_owner[objnum] == player_num));
1005
1006         if (!Network_send_objects)
1007                 return 0; // We're not sending objects to a new player
1008
1009         if (obj_mode > Network_send_object_mode)
1010                 return 0;
1011         else if (obj_mode < Network_send_object_mode)
1012                 return 1;
1013         else if (objnum < Network_send_objnum)
1014                 return 1;
1015         else
1016                 return 0;
1017 }
1018
1019 #define OBJ_PACKETS_PER_FRAME 1
1020 extern void multi_send_active_door(char);
1021 extern void multi_send_door_open_specific(int,int,int,ubyte);
1022
1023
1024 void network_send_door_updates(int pnum)
1025 {
1026         // Send door status when new player joins
1027         
1028         int i;
1029    
1030    pnum=pnum;
1031
1032 //   Assert (pnum>-1 && pnum<N_players);
1033
1034         for (i = 0; i < Num_walls; i++)
1035         {
1036       if ((Walls[i].type == WALL_DOOR) && ((Walls[i].state == WALL_DOOR_OPENING) || (Walls[i].state == WALL_DOOR_WAITING) || (Walls[i].state == WALL_DOOR_OPEN)))
1037                         multi_send_door_open_specific(pnum,Walls[i].segnum, Walls[i].sidenum,Walls[i].flags);
1038                 else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].flags & WALL_BLASTED))
1039                         multi_send_door_open_specific(pnum,Walls[i].segnum, Walls[i].sidenum,Walls[i].flags);
1040                 else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].hps != WALL_HPS))
1041                         multi_send_hostage_door_status(i);
1042                 else
1043                         multi_send_wall_status_specific(pnum,i,Walls[i].type,Walls[i].flags,Walls[i].state);
1044         }
1045 }
1046
1047 extern vms_vector MarkerPoint[];
1048 void network_send_markers()
1049  {
1050   // send marker positions/text to new player
1051
1052   
1053   int i;
1054   
1055   for (i=0;i<8;i++)
1056    {
1057     if (MarkerObject[(i*2)]!=-1)
1058      multi_send_drop_marker (i,MarkerPoint[(i*2)],0,MarkerMessage[i*2]);
1059     if (MarkerObject[(i*2)+1]!=-1)
1060      multi_send_drop_marker (i,MarkerPoint[(i*2)+1],1,MarkerMessage[(i*2)+1]);
1061    }
1062  }
1063
1064 void network_process_monitor_vector(int vector)
1065 {
1066         int i, j;
1067         int count = 0;
1068         segment *seg;
1069         
1070         for (i=0; i <= Highest_segment_index; i++)
1071         {
1072                 int tm, ec, bm;
1073                 seg = &Segments[i];
1074                 for (j = 0; j < 6; j++)
1075                 {
1076                         if ( ((tm = seg->sides[j].tmap_num2) != 0) &&
1077                                   ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
1078                                   ((bm = Effects[ec].dest_bm_num) != -1) )
1079                         {
1080                                 if (vector & (1 << count))
1081                                 {
1082                                         seg->sides[j].tmap_num2 = bm | (tm&0xc000);
1083                                 //      mprintf((0, "Monitor %d blown up.\n", count));
1084                                 }
1085                                 //else
1086                                   //    mprintf((0, "Monitor %d intact.\n", count));
1087                                 count++;
1088                                 Assert(count < 32);
1089                         }
1090                 }
1091         }
1092 }
1093
1094 int network_create_monitor_vector(void)
1095 {
1096         int i, j, k;
1097         int num_blown_bitmaps = 0;
1098         int monitor_num = 0;
1099         #define NUM_BLOWN_BITMAPS 20
1100         int blown_bitmaps[NUM_BLOWN_BITMAPS];
1101         int vector = 0;
1102         segment *seg;
1103
1104         for (i=0; i < Num_effects; i++)
1105         {
1106                 if (Effects[i].dest_bm_num > 0) {
1107                         for (j = 0; j < num_blown_bitmaps; j++)
1108                                 if (blown_bitmaps[j] == Effects[i].dest_bm_num)
1109                                         break;
1110                         if (j == num_blown_bitmaps) {
1111                                 blown_bitmaps[num_blown_bitmaps++] = Effects[i].dest_bm_num;
1112                                 Assert(num_blown_bitmaps < NUM_BLOWN_BITMAPS);
1113                         }
1114                 }
1115         }               
1116                 
1117 //      for (i = 0; i < num_blown_bitmaps; i++)
1118 //              mprintf((0, "Blown bitmap #%d = %d.\n", i, blown_bitmaps[i]));
1119
1120         for (i=0; i <= Highest_segment_index; i++)
1121         {
1122                 int tm, ec;
1123                 seg = &Segments[i];
1124                 for (j = 0; j < 6; j++)
1125                 {
1126                         if ((tm = seg->sides[j].tmap_num2) != 0) 
1127                         {
1128                                 if ( ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
1129                                           (Effects[ec].dest_bm_num != -1) )
1130                                 {
1131                                 //      mprintf((0, "Monitor %d intact.\n", monitor_num));
1132                                         monitor_num++;
1133                                         Assert(monitor_num < 32);
1134                                 }
1135                                 else
1136                                 {
1137                                         for (k = 0; k < num_blown_bitmaps; k++)
1138                                         {
1139                                                 if ((tm&0x3fff) == blown_bitmaps[k])
1140                                                 {
1141                                                         //mprintf((0, "Monitor %d destroyed.\n", monitor_num));
1142                                                         vector |= (1 << monitor_num);
1143                                                         monitor_num++;
1144                                                         Assert(monitor_num < 32);
1145                                                         break;
1146                                                 }
1147                                         }
1148                                 }
1149                         }
1150                 }
1151         }
1152   //    mprintf((0, "Final monitor vector %x.\n", vector));
1153         return(vector);
1154 }
1155
1156 void network_stop_resync(sequence_packet *their)
1157 {
1158         if (Network_game_type == IPX_GAME) {
1159                 if ( (!memcmp(Network_player_rejoining.player.network.ipx.node, their->player.network.ipx.node, 6)) &&
1160                           (!memcmp(Network_player_rejoining.player.network.ipx.server, their->player.network.ipx.server, 4)) &&
1161                      (!stricmp(Network_player_rejoining.player.callsign, their->player.callsign)) )
1162                 {
1163                         mprintf((0, "Aborting resync for player %s.\n", their->player.callsign));
1164                         Network_send_objects = 0;
1165                         Network_sending_extras=0;
1166                         Network_rejoined=0;
1167                         Player_joining_extras=-1;
1168                         Network_send_objnum = -1;
1169                 }
1170         } else {
1171                 if ( (Network_player_rejoining.player.network.appletalk.node == their->player.network.appletalk.node) &&
1172                          (Network_player_rejoining.player.network.appletalk.net == their->player.network.appletalk.net) &&
1173                          (!stricmp(Network_player_rejoining.player.callsign, their->player.callsign)) )
1174                 {
1175                         mprintf((0, "Aborting resync for player %s.\n", their->player.callsign));
1176                         Network_send_objects = 0;
1177                         Network_sending_extras=0;
1178                         Network_rejoined=0;
1179                         Player_joining_extras=-1;
1180                         Network_send_objnum = -1;
1181                 }
1182         }
1183 }
1184
1185 byte object_buffer[IPX_MAX_DATA_SIZE];
1186
1187 void network_send_objects(void)
1188 {
1189         short remote_objnum;
1190         byte owner;
1191         int loc, i, h;
1192
1193         static int obj_count = 0;
1194         static int frame_num = 0;
1195
1196         int obj_count_frame = 0;
1197         int player_num = Network_player_rejoining.player.connected;
1198
1199         // Send clear objects array trigger and send player num
1200
1201         Assert(Network_send_objects != 0);
1202         Assert(player_num >= 0);
1203         Assert(player_num < MaxNumNetPlayers);
1204
1205         if (Endlevel_sequence || Control_center_destroyed)
1206         {
1207                 // Endlevel started before we finished sending the goods, we'll
1208                 // have to stop and try again after the level.
1209
1210                 if (Network_game_type == IPX_GAME)
1211                         network_dump_player(Network_player_rejoining.player.network.ipx.server,Network_player_rejoining.player.network.ipx.node, DUMP_ENDLEVEL);
1212                 #ifdef MACINTOSH
1213                 else
1214                         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);
1215                 #endif
1216                 Network_send_objects = 0; 
1217                 return;
1218         }
1219
1220         for (h = 0; h < OBJ_PACKETS_PER_FRAME; h++) // Do more than 1 per frame, try to speed it up without
1221                                                                                                                           // over-stressing the receiver.
1222         {
1223                 obj_count_frame = 0;
1224                 memset(object_buffer, 0, IPX_MAX_DATA_SIZE);
1225                 object_buffer[0] = PID_OBJECT_DATA;
1226                 loc = 3;
1227         
1228                 if (Network_send_objnum == -1)
1229                 {
1230                         obj_count = 0;
1231                         Network_send_object_mode = 0;
1232 //       mprintf((0, "Sending object array to player %d.\n", player_num));
1233                         *(short *)(object_buffer+loc) = INTEL_SHORT(-1);        loc += 2;
1234                         object_buffer[loc] = player_num;                loc += 1;
1235                                                                                                         loc += 2; // Placeholder for remote_objnum, not used here
1236                         Network_send_objnum = 0;
1237                         obj_count_frame = 1;
1238                         frame_num = 0;
1239                 }
1240                 
1241                 for (i = Network_send_objnum; i <= Highest_object_index; i++)
1242                 {
1243                         if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) &&
1244                                  (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) &&
1245                                  (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE) &&
1246                                  !(Objects[i].type==OBJ_WEAPON && Objects[i].id==PMINE_ID))
1247                                 continue;
1248                         if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num)))
1249                                 continue;
1250                         if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num)))
1251                                 continue;
1252
1253                         if ( ((IPX_MAX_DATA_SIZE-1) - loc) < (sizeof(object)+5) )
1254                                 break; // Not enough room for another object
1255
1256                         obj_count_frame++;
1257                         obj_count++;
1258         
1259                         remote_objnum = objnum_local_to_remote((short)i, &owner);
1260                         Assert(owner == object_owner[i]);
1261
1262                         *(short *)(object_buffer+loc) = INTEL_SHORT((short)i);                          loc += 2;
1263                         object_buffer[loc] = owner;                                                                                     loc += 1;
1264                         *(short *)(object_buffer+loc) = INTEL_SHORT(remote_objnum);             loc += 2;
1265 #ifndef MACINTOSH
1266                         memcpy(object_buffer+loc, &Objects[i], sizeof(object)); loc += sizeof(object);
1267 #else
1268                         if (Network_game_type == IPX_GAME) {
1269                                 object tmpobj;
1270
1271                                 memcpy(&tmpobj, &(Objects[i]), sizeof(object));
1272                                 swap_object(&tmpobj);
1273                                 memcpy(&(object_buffer[loc]), &tmpobj, sizeof(object));                 loc += sizeof(object);
1274                         }
1275                         else
1276                                 memcpy(object_buffer+loc, &Objects[i], sizeof(object)); loc += sizeof(object);
1277 #endif
1278 //                      mprintf((0, "..packing object %d, remote %d\n", i, remote_objnum));
1279                 }
1280
1281                 if (obj_count_frame) // Send any objects we've buffered
1282                 {
1283                         frame_num++;
1284         
1285                         Network_send_objnum = i;
1286                         object_buffer[1] = obj_count_frame;  object_buffer[2] = frame_num;
1287 //       mprintf((0, "Object packet %d contains %d objects.\n", frame_num, obj_count_frame));
1288
1289                         Assert(loc <= IPX_MAX_DATA_SIZE);
1290
1291                         if (Network_game_type == IPX_GAME)
1292                                 ipx_send_internetwork_packet_data( object_buffer, loc, Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1293                         #ifdef MACINTOSH
1294                         else
1295                                 appletalk_send_packet_data( object_buffer, loc, Network_player_rejoining.player.network.appletalk.node,
1296                                         Network_player_rejoining.player.network.appletalk.net,
1297                                         Network_player_rejoining.player.network.appletalk.socket);
1298                         #endif
1299
1300                         // OLD ipx_send_packet_data(object_buffer, loc, &Network_player_rejoining.player.node);
1301                 }
1302
1303                 if (i > Highest_object_index)
1304                 {
1305                         if (Network_send_object_mode == 0)
1306                         {
1307                                 Network_send_objnum = 0;
1308                                 Network_send_object_mode = 1; // go to next mode
1309                         }
1310                         else 
1311                         {
1312                                 Assert(Network_send_object_mode == 1); 
1313
1314                                 frame_num++;
1315                                 // Send count so other side can make sure he got them all
1316 //                              mprintf((0, "Sending end marker in packet #%d.\n", frame_num));
1317                                 mprintf((0, "Sent %d objects.\n", obj_count));
1318                                 object_buffer[0] = PID_OBJECT_DATA;
1319                                 object_buffer[1] = 1;
1320                                 object_buffer[2] = frame_num;
1321                                 *(short *)(object_buffer+3) = INTEL_SHORT(-2);
1322                                 *(short *)(object_buffer+6) = INTEL_SHORT(obj_count);
1323                                 //OLD ipx_send_packet_data(object_buffer, 8, &Network_player_rejoining.player.node);
1324                                 if (Network_game_type == IPX_GAME)
1325                                         ipx_send_internetwork_packet_data(object_buffer, 8, 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, 8, 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                         
1334                                 // Send sync packet which tells the player who he is and to start!
1335                                 network_send_rejoin_sync(player_num);
1336                                 mprintf ((0,"VerfiyPlayerJoined is now set to %d\n",player_num));
1337                                 VerifyPlayerJoined=player_num;
1338
1339                                 // Turn off send object mode
1340                                 Network_send_objnum = -1;
1341                                 Network_send_objects = 0;
1342                                 obj_count = 0;
1343
1344                                 //if (!network_i_am_master ())
1345                                 // Int3();  // Bad!! Get Jason.  Someone goofy is trying to get ahold of the game!
1346
1347                                 Network_sending_extras=40; // start to send extras
1348                            Player_joining_extras=player_num;
1349
1350                                 return;
1351                         } // mode == 1;
1352                 } // i > Highest_object_index
1353         } // For PACKETS_PER_FRAME
1354 }
1355
1356 extern void multi_send_powerup_update();
1357
1358 void network_send_rejoin_sync(int player_num)
1359 {
1360         int i, j;
1361
1362         Players[player_num].connected = 1; // connect the new guy
1363         LastPacketTime[player_num] = timer_get_approx_seconds();
1364
1365         if (Endlevel_sequence || Control_center_destroyed)
1366         {
1367                 // Endlevel started before we finished sending the goods, we'll
1368                 // have to stop and try again after the level.
1369
1370                 if (Network_game_type == IPX_GAME)
1371                         network_dump_player(Network_player_rejoining.player.network.ipx.server,Network_player_rejoining.player.network.ipx.node, DUMP_ENDLEVEL);
1372                 #ifdef MACINTOSH
1373                 else
1374                         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);
1375                 #endif
1376                 Network_send_objects = 0; 
1377                 Network_sending_extras=0;
1378                 return;
1379         }
1380
1381         if (Network_player_added)
1382         {
1383                 Network_player_rejoining.type = PID_ADDPLAYER;
1384                 Network_player_rejoining.player.connected = player_num;
1385                 network_new_player(&Network_player_rejoining);
1386
1387                 for (i = 0; i < N_players; i++)
1388                 {
1389                         if ((i != player_num) && (i != Player_num) && (Players[i].connected))
1390                                 if (Network_game_type == IPX_GAME) {
1391                                         #ifndef MACINTOSH
1392                                         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);
1393                                         #else
1394                                         send_sequence_packet( Network_player_rejoining, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, Players[i].net_address);
1395                                         #endif
1396                                 #ifdef MACINTOSH
1397                                 } else {
1398                                         appletalk_send_packet_data( (ubyte *)&Network_player_rejoining, sizeof(sequence_packet), NetPlayers.players[i].network.appletalk.node,
1399                                                                                                 NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket);
1400                                 #endif
1401                                 }
1402                 }
1403         }       
1404
1405         // Send sync packet to the new guy
1406
1407         network_update_netgame();
1408
1409         // Fill in the kill list
1410         for (j=0; j<MAX_PLAYERS; j++)
1411         {
1412                 for (i=0; i<MAX_PLAYERS;i++)
1413                         Netgame.kills[j][i] = kill_matrix[j][i];
1414                 Netgame.killed[j] = Players[j].net_killed_total;
1415                 Netgame.player_kills[j] = Players[j].net_kills_total;
1416                 Netgame.player_score[j] = Players[j].score;
1417         }       
1418
1419         Netgame.level_time = Players[Player_num].time_level;
1420         Netgame.monitor_vector = network_create_monitor_vector();
1421
1422         mprintf((0, "Sending rejoin sync packet!!!\n"));
1423
1424         if (Network_game_type == IPX_GAME) {
1425                 #ifndef MACINTOSH       
1426                 ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1427                 ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1428                 #else
1429                 send_netgame_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node, NULL, 0);
1430                 send_netplayers_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node);
1431                 #endif
1432         #ifdef MACINTOSH
1433         } else {
1434                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.appletalk.node,
1435                                                                         Network_player_rejoining.player.network.appletalk.net,
1436                                                                         Network_player_rejoining.player.network.appletalk.socket);
1437                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.appletalk.node,
1438                                                                         Network_player_rejoining.player.network.appletalk.net,
1439                                                                         Network_player_rejoining.player.network.appletalk.socket);
1440         #endif
1441         }
1442         return;
1443 }
1444 void resend_sync_due_to_packet_loss_for_allender ()
1445 {
1446    int i,j;
1447
1448    mprintf ((0,"I'm resending a sync packet! VPJ=%d\n",VerifyPlayerJoined));
1449   
1450         network_update_netgame();
1451
1452         // Fill in the kill list
1453         for (j=0; j<MAX_PLAYERS; j++)
1454         {
1455                 for (i=0; i<MAX_PLAYERS;i++)
1456                         Netgame.kills[j][i] = kill_matrix[j][i];
1457                 Netgame.killed[j] = Players[j].net_killed_total;
1458                 Netgame.player_kills[j] = Players[j].net_kills_total;
1459                 Netgame.player_score[j] = Players[j].score;
1460         }       
1461
1462         Netgame.level_time = Players[Player_num].time_level;
1463         Netgame.monitor_vector = network_create_monitor_vector();
1464
1465         if (Network_game_type == IPX_GAME) {
1466                 #ifndef MACINTOSH       
1467                 ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1468                 ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node );
1469                 #else
1470                 send_netgame_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node, NULL, 0);
1471                 send_netplayers_packet(Network_player_rejoining.player.network.ipx.server, Network_player_rejoining.player.network.ipx.node);
1472                 #endif
1473         #ifdef MACINTOSH
1474         } else {
1475                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.network.appletalk.node,
1476                                                                         Network_player_rejoining.player.network.appletalk.net,
1477                                                                         Network_player_rejoining.player.network.appletalk.socket);
1478                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), Network_player_rejoining.player.network.appletalk.node,
1479                                                                         Network_player_rejoining.player.network.appletalk.net,
1480                                                                         Network_player_rejoining.player.network.appletalk.socket);
1481         #endif
1482         }
1483 }
1484
1485
1486 char * network_get_player_name( int objnum )
1487 {
1488         if ( objnum < 0 ) return NULL; 
1489         if ( Objects[objnum].type != OBJ_PLAYER ) return NULL;
1490         if ( Objects[objnum].id >= MAX_PLAYERS ) return NULL;
1491         if ( Objects[objnum].id >= N_players ) return NULL;
1492         
1493         return Players[Objects[objnum].id].callsign;
1494 }
1495
1496
1497 void network_add_player(sequence_packet *p)
1498 {
1499         int i;
1500         
1501         mprintf((0, "Got add player request!\n"));
1502
1503         for (i=0; i<N_players; i++ )    {
1504                 if (Network_game_type == IPX_GAME) {
1505                         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)) 
1506                                 return;         // already got them
1507                 } else {
1508                         if ( (NetPlayers.players[i].network.appletalk.node == p->player.network.appletalk.node) &&
1509                                  (NetPlayers.players[i].network.appletalk.net == p->player.network.appletalk.net))
1510                                         return;
1511                 }
1512         }
1513
1514         if (Network_game_type == IPX_GAME) {
1515                 memcpy( NetPlayers.players[N_players].network.ipx.node, p->player.network.ipx.node, 6 );
1516                 memcpy( NetPlayers.players[N_players].network.ipx.server, p->player.network.ipx.server, 4 );
1517         } else {
1518                 NetPlayers.players[N_players].network.appletalk.node = p->player.network.appletalk.node;
1519                 NetPlayers.players[N_players].network.appletalk.net = p->player.network.appletalk.net;
1520                 NetPlayers.players[N_players].network.appletalk.socket = p->player.network.appletalk.socket;
1521         }
1522    
1523    ClipRank (&p->player.rank);
1524   
1525         memcpy( NetPlayers.players[N_players].callsign, p->player.callsign, CALLSIGN_LEN+1 );
1526         NetPlayers.players[N_players].version_major=p->player.version_major;
1527         NetPlayers.players[N_players].version_minor=p->player.version_minor;
1528    NetPlayers.players[N_players].rank=p->player.rank;
1529         NetPlayers.players[N_players].connected = 1;
1530    network_check_for_old_version (N_players);
1531
1532         Players[N_players].KillGoalCount=0;
1533         Players[N_players].connected = 1;
1534         LastPacketTime[N_players] = timer_get_approx_seconds();
1535         N_players++;
1536         Netgame.numplayers = N_players;
1537
1538         // Broadcast updated info
1539
1540    mprintf ((0,"sending_game_info!\n"));
1541         network_send_game_info(NULL);
1542 }
1543
1544 // One of the players decided not to join the game
1545
1546 void network_remove_player(sequence_packet *p)
1547 {
1548         int i,pn;
1549         
1550         pn = -1;
1551         for (i=0; i<N_players; i++ )    {
1552                 if (Network_game_type == IPX_GAME) {
1553                         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)) {
1554                                 pn = i;
1555                                 break;
1556                         }
1557                 } else {
1558                         if ( (NetPlayers.players[i].network.appletalk.node == p->player.network.appletalk.node) && (NetPlayers.players[i].network.appletalk.net == p->player.network.appletalk.net) ) {
1559                                 pn = i;
1560                                 break;
1561                         }
1562                 }
1563         }
1564         
1565         if (pn < 0 ) return;
1566
1567         for (i=pn; i<N_players-1; i++ ) {
1568                 if (Network_game_type == IPX_GAME) {
1569                         memcpy( NetPlayers.players[i].network.ipx.node, NetPlayers.players[i+1].network.ipx.node, 6 );
1570                         memcpy( NetPlayers.players[i].network.ipx.server, NetPlayers.players[i+1].network.ipx.server, 4 );
1571                 } else {
1572                         NetPlayers.players[i].network.appletalk.node = NetPlayers.players[i+1].network.appletalk.node;
1573                         NetPlayers.players[i].network.appletalk.net = NetPlayers.players[i+1].network.appletalk.net;
1574                         NetPlayers.players[i].network.appletalk.socket = NetPlayers.players[i+1].network.appletalk.socket;
1575                 }
1576                 memcpy( NetPlayers.players[i].callsign, NetPlayers.players[i+1].callsign, CALLSIGN_LEN+1 );
1577                 NetPlayers.players[i].version_major=NetPlayers.players[i+1].version_major;
1578                 NetPlayers.players[i].version_minor=NetPlayers.players[i+1].version_minor;
1579
1580            NetPlayers.players[i].rank=NetPlayers.players[i+1].rank;
1581                 ClipRank (&NetPlayers.players[i].rank);
1582            network_check_for_old_version(i);    
1583         }
1584                 
1585         N_players--;
1586         Netgame.numplayers = N_players;
1587
1588         // Broadcast new info
1589
1590         network_send_game_info(NULL);
1591
1592 }
1593
1594 void
1595 network_dump_player(ubyte * server, ubyte *node, int why)
1596 {
1597         // Inform player that he was not chosen for the netgame
1598
1599         sequence_packet temp;
1600
1601         temp.type = PID_DUMP;
1602         memcpy(temp.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
1603         temp.player.connected = why;
1604         if (Network_game_type == IPX_GAME) {
1605                 #ifndef MACINTOSH
1606                 ipx_send_internetwork_packet_data( (ubyte *)&temp, sizeof(sequence_packet), server, node);
1607                 #else
1608                 send_sequence_packet( temp, server, node, NULL);
1609                 #endif
1610         } else {
1611                 Int3();
1612         }
1613 }
1614
1615 #ifdef MACINTOSH
1616 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why)
1617 {
1618         sequence_packet temp;
1619
1620         temp.type = PID_DUMP;
1621         memcpy(temp.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
1622         temp.player.connected = why;
1623         if (Network_game_type == APPLETALK_GAME) {
1624                 appletalk_send_packet_data( (ubyte *)&temp, sizeof(sequence_packet), node, net, socket );
1625         } else {
1626                 Int3();
1627         }
1628 }
1629 #endif
1630
1631 void
1632 network_send_game_list_request()
1633 {
1634         // Send a broadcast request for game info
1635
1636         sequence_packet me;
1637
1638         mprintf((0, "Sending game_list request.\n"));
1639         me.type = PID_GAME_LIST;
1640         memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
1641
1642         if (Network_game_type == IPX_GAME) {
1643                 memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
1644                 memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
1645
1646                 #ifndef MACINTOSH       
1647                 ipx_send_broadcast_packet_data( (ubyte *)&me, sizeof(sequence_packet) );
1648                 #else
1649                 send_sequence_packet( me, NULL, NULL, NULL);
1650                 #endif
1651         #ifdef MACINTOSH
1652         } else {
1653                 me.player.network.appletalk.node = appletalk_get_my_node();
1654                 me.player.network.appletalk.net = appletalk_get_my_net();
1655                 me.player.network.appletalk.socket = appletalk_get_my_socket();
1656                 appletalk_send_game_info( (ubyte *)&me, sizeof(sequence_packet), Network_zone_name );
1657         #endif
1658         }
1659 }
1660
1661 void network_send_all_info_request(char type,int which_security)
1662 {
1663         // Send a broadcast request for game info
1664
1665         sequence_packet me;
1666
1667         mprintf((0, "Sending all_info request.\n"));
1668    
1669         me.Security=which_security;
1670         me.type = type;
1671         memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
1672         
1673         if (Network_game_type == IPX_GAME) {
1674                 memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
1675                 memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
1676
1677                 #ifndef MACINTOSH       
1678                 ipx_send_broadcast_packet_data( (ubyte *)&me, sizeof(sequence_packet) );
1679                 #else
1680                 send_sequence_packet(me, NULL, NULL, NULL);
1681                 #endif
1682         #ifdef MACINTOSH
1683         } else {
1684                 me.player.network.appletalk.node = appletalk_get_my_node();
1685                 me.player.network.appletalk.net = appletalk_get_my_net();
1686                 me.player.network.appletalk.socket = appletalk_get_my_socket();
1687                 appletalk_send_game_info( (ubyte *)&me, sizeof(sequence_packet), Network_zone_name );
1688         #endif
1689         }
1690 }
1691
1692
1693 void
1694 network_update_netgame(void)
1695 {
1696         // Update the netgame struct with current game variables
1697
1698         int i, j;
1699
1700    Netgame.numconnected=0;
1701    for (i=0;i<N_players;i++)
1702          if (Players[i].connected)
1703                 Netgame.numconnected++;
1704
1705 // This is great: D2 1.0 and 1.1 ignore upper part of the game_flags field of
1706 //      the lite_info struct when you're sitting on the join netgame screen.  We can
1707 //      "sneak" Hoard information into this field.  This is better than sending 
1708 //      another packet that could be lost in transit.
1709
1710
1711         if (HoardEquipped())
1712         {
1713                 if (Game_mode & GM_HOARD)
1714                 {
1715                         Netgame.game_flags |=NETGAME_FLAG_HOARD;
1716                         if (Game_mode & GM_TEAM)
1717                                 Netgame.game_flags |=NETGAME_FLAG_TEAM_HOARD;
1718                 }
1719         }
1720  
1721         if (Network_status == NETSTAT_STARTING)
1722                 return;
1723
1724         Netgame.numplayers = N_players;
1725         Netgame.game_status = Network_status;
1726         Netgame.max_numplayers = MaxNumNetPlayers;
1727
1728         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++) 
1729         {
1730                 NetPlayers.players[i].connected = Players[i].connected;
1731                 for(j = 0; j < MAX_NUM_NET_PLAYERS; j++)
1732                         Netgame.kills[i][j] = kill_matrix[i][j];
1733
1734                 Netgame.killed[i] = Players[i].net_killed_total;
1735                 Netgame.player_kills[i] = Players[i].net_kills_total;
1736                 Netgame.player_score[i] = Players[i].score;
1737                 Netgame.player_flags[i] = (Players[i].flags & (PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY));
1738         }
1739         Netgame.team_kills[0] = team_kills[0];
1740         Netgame.team_kills[1] = team_kills[1];
1741         Netgame.levelnum = Current_level_num;
1742
1743  
1744 }
1745
1746 void
1747 network_send_endlevel_sub(int player_num)
1748 {
1749         endlevel_info end;
1750         int i, j;
1751
1752         // Send an endlevel packet for a player
1753         end.type                = PID_ENDLEVEL;
1754         end.player_num = player_num;
1755         end.connected   = Players[player_num].connected;
1756         end.kills               = INTEL_SHORT(Players[player_num].net_kills_total);
1757         end.killed              = INTEL_SHORT(Players[player_num].net_killed_total);
1758         memcpy(end.kill_matrix, kill_matrix[player_num], MAX_PLAYERS*sizeof(short));
1759 #ifdef MACINTOSH
1760         for (i = 0; i < MAX_PLAYERS; i++)
1761                 for (j = 0; j < MAX_PLAYERS; j++)
1762                         end.kill_matrix[i][j] = INTEL_SHORT(end.kill_matrix[i][j]);
1763 #else
1764         j = j;          // to satisfy compiler
1765 #endif
1766
1767         if (Players[player_num].connected == 1) // Still playing
1768         {
1769                 Assert(Control_center_destroyed);
1770                 end.seconds_left = Countdown_seconds_left;
1771         }
1772
1773 //      mprintf((0, "Sending endlevel packet.\n"));
1774
1775         for (i = 0; i < N_players; i++)
1776         {       
1777                 if ((i != Player_num) && (i!=player_num) && (Players[i].connected)) {
1778                   if (Players[i].connected==1)
1779                          network_send_endlevel_short_sub(player_num,i);
1780                   else {
1781                         if (Network_game_type == IPX_GAME)
1782                                 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);
1783                         #ifdef MACINTOSH
1784                         else
1785                                 appletalk_send_packet_data( (ubyte *)&end, sizeof(endlevel_info), NetPlayers.players[i].network.appletalk.node,
1786                                                                                         NetPlayers.players[i].network.appletalk.net,
1787                                                                                         NetPlayers.players[i].network.appletalk.socket);
1788                         #endif
1789                         }       
1790                 }
1791         }
1792 }
1793
1794 void
1795 network_send_endlevel_packet(void)
1796 {
1797         // Send an updated endlevel status to other hosts
1798
1799         network_send_endlevel_sub(Player_num);
1800 }
1801
1802
1803 void
1804 network_send_endlevel_short_sub(int from_player_num,int to_player)
1805 {
1806         endlevel_info_short end;
1807
1808         // Send an endlevel packet for a player
1809         end.type                = PID_ENDLEVEL_SHORT;
1810         end.player_num = from_player_num;
1811         end.connected   = Players[from_player_num].connected;
1812         end.seconds_left = Countdown_seconds_left;
1813
1814
1815         if (Players[from_player_num].connected == 1) // Still playing
1816         {
1817                 Assert(Control_center_destroyed);
1818         }
1819
1820         if ((to_player != Player_num) && (to_player!=from_player_num) && (Players[to_player].connected))
1821         {
1822                 mprintf((0, "Sending short endlevel packet to %s.\n",Players[to_player].callsign));
1823                 if (Network_game_type == IPX_GAME)
1824                         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);
1825                 #ifdef MACINTOSH
1826                 else
1827                         appletalk_send_packet_data( (ubyte *)&end, sizeof(endlevel_info_short), NetPlayers.players[to_player].network.appletalk.node,
1828                                                                                 NetPlayers.players[to_player].network.appletalk.net,
1829                                                                                 NetPlayers.players[to_player].network.appletalk.socket);
1830                 #endif
1831         }
1832 }
1833
1834 extern fix ThisLevelTime;
1835
1836 void
1837 network_send_game_info(sequence_packet *their)
1838 {
1839         // Send game info to someone who requested it
1840
1841         char old_type, old_status;
1842    fix timevar;
1843    int i;
1844
1845         mprintf((0, "Sending game info.\n"));
1846
1847         network_update_netgame(); // Update the values in the netgame struct
1848
1849         old_type = Netgame.type;
1850         old_status = Netgame.game_status;
1851
1852         Netgame.type = PID_GAME_INFO;
1853    NetPlayers.type = PID_PLAYERSINFO;
1854
1855    NetPlayers.Security=Netgame.Security;
1856         Netgame.version_major=Version_major;
1857         Netgame.version_minor=Version_minor;
1858
1859         if (Endlevel_sequence || Control_center_destroyed)
1860                 Netgame.game_status = NETSTAT_ENDLEVEL;
1861
1862         if (Netgame.PlayTimeAllowed)
1863     {
1864                 timevar=i2f (Netgame.PlayTimeAllowed*5*60);
1865                 i=f2i(timevar-ThisLevelTime);
1866                 if (i<30)
1867                         Netgame.game_status=NETSTAT_ENDLEVEL;
1868         }       
1869
1870         if (!their) {
1871                 if (Network_game_type == IPX_GAME) {
1872                         #ifndef MACINTOSH
1873                         ipx_send_broadcast_packet_data((ubyte *)&Netgame, sizeof(netgame_info));
1874                         ipx_send_broadcast_packet_data((ubyte *)&NetPlayers,sizeof(AllNetPlayers_info));
1875                         #else
1876                         send_netgame_packet(NULL, NULL, NULL, 0);               // server == NULL says to broadcast packet
1877                         send_netplayers_packet(NULL, NULL);
1878                         #endif
1879                 } // nothing to do for appletalk games I think....
1880         } else {
1881                 if (Network_game_type == IPX_GAME) {
1882                         #ifndef MACINTOSH        
1883                     ipx_send_internetwork_packet_data((ubyte *)&Netgame, sizeof(netgame_info), their->player.network.ipx.server, their->player.network.ipx.node);
1884                         ipx_send_internetwork_packet_data((ubyte *)&NetPlayers,sizeof(AllNetPlayers_info),their->player.network.ipx.server,their->player.network.ipx.node);
1885                         #else
1886                         send_netgame_packet(their->player.network.ipx.server, their->player.network.ipx.node, NULL, 0);
1887                         send_netplayers_packet(their->player.network.ipx.server, their->player.network.ipx.node);
1888                         #endif
1889                 #ifdef MACINTOSH
1890                 } else {
1891                         appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), their->player.network.appletalk.node,
1892                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1893                         appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), their->player.network.appletalk.node,
1894                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1895                 #endif
1896                 }
1897         }  
1898
1899         Netgame.type = old_type;
1900         Netgame.game_status = old_status;
1901 }       
1902
1903 void network_send_lite_info(sequence_packet *their)
1904 {
1905         // Send game info to someone who requested it
1906
1907         char old_type, old_status,oldstatus;
1908
1909         mprintf((0, "Sending lite game info.\n"));
1910
1911         network_update_netgame(); // Update the values in the netgame struct
1912
1913         old_type = Netgame.type;
1914         old_status = Netgame.game_status;
1915
1916         Netgame.type = PID_LITE_INFO;
1917
1918         if (Endlevel_sequence || Control_center_destroyed)
1919                 Netgame.game_status = NETSTAT_ENDLEVEL;
1920
1921 // If hoard mode, make this game look closed even if it isn't
1922    if (HoardEquipped())
1923         {
1924                 if (Game_mode & GM_HOARD)
1925                 {
1926                         oldstatus=Netgame.game_status;
1927                         Netgame.game_status=NETSTAT_ENDLEVEL;
1928                         Netgame.gamemode=NETGAME_CAPTURE_FLAG;
1929                         if (oldstatus==NETSTAT_ENDLEVEL)
1930                                 Netgame.game_flags|=NETGAME_FLAG_REALLY_ENDLEVEL;
1931                         if (oldstatus==NETSTAT_STARTING)
1932                                 Netgame.game_flags|=NETGAME_FLAG_REALLY_FORMING;
1933                 }
1934         }
1935
1936         if (!their) {
1937                 if (Network_game_type == IPX_GAME) {
1938                         #ifndef MACINTOSH
1939                         ipx_send_broadcast_packet_data((ubyte *)&Netgame, sizeof(lite_info));
1940                         #else
1941                         send_netgame_packet(NULL, NULL, NULL, 1);                       // server == NULL says broadcast
1942                         #endif
1943                 }               // nothing to do for appletalk I think....
1944         } else {
1945                 if (Network_game_type == IPX_GAME) {
1946                         #ifndef MACINTOSH
1947                     ipx_send_internetwork_packet_data((ubyte *)&Netgame, sizeof(lite_info), their->player.network.ipx.server, their->player.network.ipx.node);
1948                         #else
1949                         send_netgame_packet(their->player.network.ipx.server, their->player.network.ipx.node, NULL, 1);
1950                         #endif
1951                 #ifdef MACINTOSH
1952                 } else {
1953                         appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(lite_info), their->player.network.appletalk.node,
1954                                                                                 their->player.network.appletalk.net, their->player.network.appletalk.socket );
1955                 #endif
1956                 }
1957         }  
1958
1959         //  Restore the pre-hoard mode
1960         if (HoardEquipped())
1961         {
1962                 if (Game_mode & GM_HOARD)
1963                 {
1964                         if (!(Game_mode & GM_TEAM))
1965                            Netgame.gamemode=NETGAME_HOARD;
1966                         else
1967                            Netgame.gamemode=NETGAME_TEAM_HOARD;
1968                         Netgame.game_flags&=~NETGAME_FLAG_REALLY_ENDLEVEL;
1969                         Netgame.game_flags&=~NETGAME_FLAG_REALLY_FORMING;
1970                         Netgame.game_flags&=~NETGAME_FLAG_TEAM_HOARD;
1971                 }
1972         }
1973
1974         Netgame.type = old_type;
1975         Netgame.game_status = old_status;
1976
1977 }       
1978
1979 void network_send_netgame_update()
1980 {
1981         // Send game info to someone who requested it
1982
1983         char old_type, old_status,i;
1984
1985         mprintf((0, "Sending updated game info.\n"));
1986
1987         network_update_netgame(); // Update the values in the netgame struct
1988
1989         old_type = Netgame.type;
1990         old_status = Netgame.game_status;
1991
1992         Netgame.type = PID_GAME_UPDATE;
1993
1994         if (Endlevel_sequence || Control_center_destroyed)
1995                 Netgame.game_status = NETSTAT_ENDLEVEL;
1996  
1997         for (i=0; i<N_players; i++ )    {
1998                 if ( (Players[i].connected) && (i!=Player_num ) )       {
1999                         if (Network_game_type == IPX_GAME) {
2000                                 #ifndef MACINTOSH
2001                                 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 );
2002                                 #else
2003                                 send_netgame_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, Players[i].net_address, 0);
2004                                 #endif
2005                         #ifdef MACINTOSH
2006                         } else {
2007                                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(lite_info), NetPlayers.players[i].network.appletalk.node,
2008                                                                                         NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket );
2009                         #endif
2010                         }
2011                 }
2012         }
2013
2014         Netgame.type = old_type;
2015         Netgame.game_status = old_status;
2016 }       
2017                           
2018 int network_send_request(void)
2019 {
2020         // Send a request to join a game 'Netgame'.  Returns 0 if we can join this
2021         // game, non-zero if there is some problem.
2022         int i;
2023
2024         if (Netgame.numplayers < 1)
2025          return 1;
2026
2027         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
2028           if (NetPlayers.players[i].connected)
2029               break;
2030
2031         Assert(i < MAX_NUM_NET_PLAYERS);
2032
2033         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));
2034
2035 //      segments_checksum = netmisc_calc_checksum( Segments, sizeof(segment)*(Highest_segment_index+1) );       
2036
2037         My_Seq.type = PID_REQUEST;
2038         My_Seq.player.connected = Current_level_num;
2039
2040         if (Network_game_type == IPX_GAME) {
2041                 #ifndef MACINTOSH
2042                 ipx_send_internetwork_packet_data((ubyte *)&My_Seq, sizeof(sequence_packet), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
2043                 #else
2044                 send_sequence_packet(My_Seq, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, NULL);
2045                 #endif
2046         #ifdef MACINTOSH
2047         } else {
2048                 appletalk_send_packet_data( (ubyte *)&My_Seq, sizeof(sequence_packet), NetPlayers.players[i].network.appletalk.node,
2049                                                                         NetPlayers.players[i].network.appletalk.net,
2050                                                                         NetPlayers.players[i].network.appletalk.socket);
2051         #endif
2052         }
2053
2054         return i;
2055 }
2056
2057 int SecurityCheck=0;
2058         
2059 void network_process_gameinfo(ubyte *data)
2060 {
2061 #ifdef MACINTOSH
2062         netgame_info tmp_info;
2063 #endif
2064         int i, j;
2065         netgame_info *new = (netgame_info *)data;
2066
2067 #ifdef MACINTOSH
2068         if (Network_game_type == IPX_GAME)  {
2069                 receive_netgame_packet(data, &tmp_info, 0);                     // get correctly aligned structure
2070                 new = &tmp_info;
2071         }
2072 #endif
2073         
2074
2075    WaitingForPlayerInfo=0;
2076
2077    if (new->Security !=TempPlayersInfo->Security)
2078     {
2079      Int3();     // Get Jason
2080      return;     // If this first half doesn't go with the second half
2081     }
2082
2083         Network_games_changed = 1;
2084
2085    //mprintf((0, "Got game data for game %s.\n", new->game_name));
2086
2087    Assert (TempPlayersInfo!=NULL);
2088
2089         for (i = 0; i < num_active_games; i++)
2090          {
2091           //mprintf ((0,"GAMEINFO: Game %d is %s!\n",i,Active_games[i].game_name));
2092           
2093           if (!stricmp(Active_games[i].game_name, new->game_name) && 
2094                                   Active_games[i].Security==new->Security)
2095                break;
2096          }
2097
2098         if (i == MAX_ACTIVE_NETGAMES)
2099         {
2100                 mprintf((0, "Too many netgames.\n"));
2101                 return;
2102         }
2103         
2104 // MWA  memcpy(&Active_games[i], data, sizeof(netgame_info));
2105         memcpy(&Active_games[i], (ubyte *)new, sizeof(netgame_info));
2106         memcpy (&ActiveNetPlayers[i],TempPlayersInfo,sizeof(AllNetPlayers_info));
2107
2108    if (SecurityCheck)
2109          if (Active_games[i].Security==SecurityCheck)
2110                 SecurityCheck=-1;
2111
2112         //mprintf ((0,"Recieved %d unique games...\n",i));
2113
2114         if (i == num_active_games)
2115                 num_active_games++;
2116
2117         if (Active_games[i].numplayers == 0)
2118         {
2119          mprintf ((0,"DELETING THIS GAME!!!\n"));       
2120                 // Delete this game
2121                 for (j = i; j < num_active_games-1; j++)
2122         {
2123              memcpy(&Active_games[j], &Active_games[j+1], sizeof(netgame_info));
2124            memcpy (&ActiveNetPlayers[j],&ActiveNetPlayers[j+1],sizeof(AllNetPlayers_info));
2125         }
2126                 num_active_games--;
2127                 SecurityCheck=0;
2128         }
2129 }
2130
2131 void network_process_lite_info(ubyte *data)
2132 {
2133 #ifdef MACINTOSH
2134         lite_info tmp_info;
2135 #endif
2136         int i, j;
2137         lite_info *new = (lite_info *)data;
2138
2139 #ifdef MACINTOSH
2140         if (Network_game_type == IPX_GAME) {
2141                 receive_netgame_packet(data, (netgame_info *)&tmp_info, 1);
2142                 new = &tmp_info;
2143         }
2144 #endif
2145
2146         Network_games_changed = 1;
2147
2148    //mprintf((0, "Got game data for game %s.\n", new->game_name));
2149
2150         for (i = 0; i < num_active_games; i++)
2151     {
2152       //mprintf ((0,"GAMEINFO: Game %d is %s!\n",i,Active_games[i].game_name));
2153       
2154       if ((!stricmp(Active_games[i].game_name, new->game_name)) && 
2155                          Active_games[i].Security==new->Security)
2156                                 break;
2157     }
2158
2159         if (i == MAX_ACTIVE_NETGAMES)
2160         {
2161                 mprintf((0, "Too many netgames.\n"));
2162                 return;
2163         }
2164         
2165         memcpy(&Active_games[i], (ubyte *)new, sizeof(lite_info));
2166
2167 // See if this is really a Hoard game
2168 // If so, adjust all the data accordingly
2169
2170         if (HoardEquipped())
2171         {
2172                 if (Active_games[i].game_flags & NETGAME_FLAG_HOARD)
2173                 {
2174                         Active_games[i].gamemode=NETGAME_HOARD;                                   
2175                         Active_games[i].game_status=NETSTAT_PLAYING;
2176                         
2177                         if (Active_games[i].game_flags & NETGAME_FLAG_TEAM_HOARD)
2178                                 Active_games[i].gamemode=NETGAME_TEAM_HOARD;                                      
2179                         if (Active_games[i].game_flags & NETGAME_FLAG_REALLY_ENDLEVEL)
2180                                 Active_games[i].game_status=NETSTAT_ENDLEVEL;
2181                         if (Active_games[i].game_flags & NETGAME_FLAG_REALLY_FORMING)
2182                                 Active_games[i].game_status=NETSTAT_STARTING;
2183                 }
2184         }
2185
2186    //mprintf ((0,"Recieved %d unique games...\n",i));
2187
2188         if (i == num_active_games)
2189                 num_active_games++;
2190
2191         if (Active_games[i].numplayers == 0)
2192     {
2193            mprintf ((0,"DELETING THIS GAME!!!\n"));     
2194                 // Delete this game
2195                 for (j = i; j < num_active_games-1; j++)
2196         {
2197              memcpy(&Active_games[j], &Active_games[j+1], sizeof(netgame_info));
2198         }
2199                 num_active_games--;
2200         }
2201 }
2202
2203 void network_process_dump(sequence_packet *their)
2204 {
2205         // Our request for join was denied.  Tell the user why.
2206
2207    char temp[40],i;
2208  
2209         mprintf((0, "Dumped by player %s, type %d.\n", their->player.callsign, their->player.connected));
2210
2211    if (their->player.connected!=7)
2212                 nm_messagebox(NULL, 1, TXT_OK, NET_DUMP_STRINGS(their->player.connected));
2213         else
2214                 {
2215                  for (i=0;i<N_players;i++)
2216                         if (!stricmp (their->player.callsign,Players[i].callsign))
2217                         {
2218                                 if (i!=network_who_is_master())
2219                                 {
2220                                         HUD_init_message ("%s attempted to kick you out.",their->player.callsign);
2221                                 }
2222                                 else
2223                                 {
2224                                   sprintf (temp,"%s has kicked you out!",their->player.callsign);
2225                                   nm_messagebox(NULL, 1, TXT_OK, &temp);
2226                             if (Network_status==NETSTAT_PLAYING)
2227                                   {
2228                                         IWasKicked=1;
2229                                         multi_leave_game();     
2230                                   }
2231                                  else
2232                                         Network_status = NETSTAT_MENU;
2233                       }
2234                    }
2235                 }
2236 }       
2237 void network_process_request(sequence_packet *their)
2238 {
2239         // Player is ready to receieve a sync packet
2240         int i;
2241
2242         mprintf((0, "Player %s ready for sync.\n", their->player.callsign));
2243
2244         for (i = 0; i < N_players; i++) {
2245                 if (Network_game_type == IPX_GAME) {
2246                         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))) {
2247                                 Players[i].connected = 1;
2248                                 break;
2249                         }
2250                 } else {
2251                         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)) ) {
2252                                 Players[i].connected = 1;
2253                                 break;
2254                         }
2255                 }
2256         }                       
2257 }
2258
2259 #define REFUSE_INTERVAL F1_0 * 8
2260 extern void multi_reset_object_texture (object *);
2261
2262 void network_process_packet(ubyte *data, int length )
2263 {
2264 #ifdef MACINTOSH
2265         sequence_packet tmp_packet;
2266 #endif
2267         sequence_packet *their = (sequence_packet *)data;
2268
2269 #ifdef MACINTOSH
2270         if (Network_game_type == IPX_GAME) {
2271                 receive_sequence_packet(data, &tmp_packet);
2272                 their = &tmp_packet;                                            // reassign their to point to correctly alinged structure
2273         }
2274 #endif
2275
2276    //mprintf( (0, "Got packet of length %d, type %d\n", length, their->type ));
2277         
2278 //      if ( length < sizeof(sequence_packet) ) return;
2279
2280         length = length;
2281
2282         switch( data[0] )       {
2283         
2284          case PID_GAME_INFO:            // Jason L. says we can safely ignore this type.
2285                 break;
2286         
2287      case PID_PLAYERSINFO:
2288
2289                 mprintf ((0,"Got a PID_PLAYERSINFO!\n"));
2290
2291                 if (Network_status==NETSTAT_WAITING)
2292                 {
2293 #ifndef MACINTOSH                        
2294                         memcpy (&TempPlayersBase,data,sizeof(AllNetPlayers_info));
2295 #else
2296                         if (Network_game_type == IPX_GAME)
2297                                 receive_netplayers_packet(data, &TempPlayersBase);
2298                         else
2299                                 memcpy (&TempPlayersBase,data,sizeof(AllNetPlayers_info));
2300 #endif
2301
2302                         if (TempPlayersBase.Security!=Netgame.Security)
2303                          {
2304                           mprintf ((0,"Bad security for PLAYERSINFO\n"));
2305                           break;
2306                          }      
2307                 
2308                         mprintf ((0,"Got a waiting PID_PLAYERSINFO!\n"));
2309                         if (length!=ALLNETPLAYERSINFO_SIZE)
2310                         {
2311                                 mprintf ((0,"Invalid size for netplayers packet!\n"));
2312                                 return;
2313                         }
2314
2315                         TempPlayersInfo=&TempPlayersBase;
2316                         WaitingForPlayerInfo=0;
2317                         NetSecurityNum=TempPlayersInfo->Security;
2318                         NetSecurityFlag=NETSECURITY_WAIT_FOR_SYNC;
2319            }
2320
2321      break;
2322
2323    case PID_LITE_INFO:
2324
2325          if (length != LITE_INFO_SIZE)
2326                  {
2327                   mprintf ((0,"WARNING! Recieved invalid size for PID_LITE_INFO\n"));
2328                   return;
2329                  }
2330  
2331          if (Network_status == NETSTAT_BROWSING)
2332                 network_process_lite_info (data);
2333     break;
2334
2335         case PID_GAME_LIST:
2336                 // Someone wants a list of games
2337
2338            if (length != SEQUENCE_PACKET_SIZE)
2339                  {
2340                   mprintf ((0,"WARNING! Recieved invalid size for PID_GAME_LIST\n"));
2341                   return;
2342                  }
2343                         
2344                 mprintf((0, "Got a PID_GAME_LIST!\n"));
2345                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2346                         if (network_i_am_master())
2347                                 network_send_lite_info(their);
2348                 break;
2349
2350
2351         case PID_SEND_ALL_GAMEINFO:
2352
2353            if (length != SEQUENCE_PACKET_SIZE)
2354                  {
2355                   mprintf ((0,"WARNING! Recieved invalid size for PID_SEND_ALL_GAMEINFO\n"));
2356                   return;
2357                  }
2358
2359                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2360                         if (network_i_am_master() && their->Security==Netgame.Security)
2361                                 network_send_game_info(their);
2362                 break;
2363         
2364         case PID_ADDPLAYER:
2365
2366                 mprintf( (0, "Got NEWPLAYER message from %s.\n", their->player.callsign));
2367                 
2368            if (length != SEQUENCE_PACKET_SIZE)
2369                  {
2370                   mprintf ((0,"WARNING! Recieved invalid size for PID_ADDPLAYER\n"));
2371                   return;
2372                  }
2373                 mprintf( (0, "Got NEWPLAYER message from %s.\n", their->player.callsign));
2374                 network_new_player(their);
2375                 break;                  
2376         case PID_REQUEST:
2377            if (length != SEQUENCE_PACKET_SIZE)
2378                  {
2379                   mprintf ((0,"WARNING! Recieved invalid size for PID_REQUEST\n"));
2380                   return;
2381                  }
2382
2383                 mprintf( (0, "Got REQUEST from '%s'\n", their->player.callsign ));
2384                 if (Network_status == NETSTAT_STARTING) 
2385                 {
2386                         // Someone wants to join our game!
2387                         network_add_player(their);
2388                 }
2389                 else if (Network_status == NETSTAT_WAITING)
2390                 {
2391                         // Someone is ready to recieve a sync packet
2392                         network_process_request(their);
2393                 }
2394                 else if (Network_status == NETSTAT_PLAYING)
2395                 {
2396                         // Someone wants to join a game in progress!
2397                         if (Netgame.RefusePlayers)
2398                 DoRefuseStuff (their);
2399                    else 
2400                                 network_welcome_player(their);
2401                 }
2402                 break;
2403         case PID_DUMP:  
2404
2405            if (length != SEQUENCE_PACKET_SIZE)
2406                  {
2407                   mprintf ((0,"WARNING! Recieved invalid size for PID_DUMP\n"));
2408                   return;
2409                  }
2410   
2411                 if (Network_status == NETSTAT_WAITING || Network_status==NETSTAT_PLAYING )
2412                         network_process_dump(their);
2413                 break;
2414         case PID_QUIT_JOINING:
2415
2416            if (length != SEQUENCE_PACKET_SIZE)
2417                  {
2418                   mprintf ((0,"WARNING! Recieved invalid size for PID_QUIT_JOINING\n"));
2419                   return;
2420                  }
2421                 if (Network_status == NETSTAT_STARTING)
2422                         network_remove_player( their );
2423                 else if ((Network_status == NETSTAT_PLAYING) && (Network_send_objects))
2424                         network_stop_resync( their );
2425                 break;
2426         case PID_SYNC:  
2427
2428                 mprintf ((0,"Got a sync packet! Network_status=%d\n",NETSTAT_WAITING));
2429
2430                 if (Network_status == NETSTAT_WAITING)  {
2431
2432 #ifndef MACINTOSH
2433                         memcpy((ubyte *)&(TempNetInfo), data, sizeof(netgame_info));
2434 #else
2435                         if (Network_game_type == IPX_GAME)
2436                                 receive_netgame_packet(data, &TempNetInfo, 0);
2437                         else
2438                                 memcpy((ubyte *)&(TempNetInfo), data, sizeof(netgame_info));
2439 #endif
2440
2441                         if (TempNetInfo.Security!=Netgame.Security)
2442                          {
2443                                 mprintf ((0,"Bad security on sync packet.\n"));
2444                                 break;
2445                          }
2446
2447                         if (NetSecurityFlag==NETSECURITY_WAIT_FOR_SYNC)
2448                          {
2449                           if (TempNetInfo.Security==TempPlayersInfo->Security)
2450                           {
2451                                 network_read_sync_packet (&TempNetInfo,0);
2452                                 NetSecurityFlag=0;
2453                                 NetSecurityNum=0;
2454                           }     
2455                          }
2456                         else
2457                          {      
2458                         NetSecurityFlag=NETSECURITY_WAIT_FOR_PLAYERS;
2459                         NetSecurityNum=TempNetInfo.Security;
2460
2461                         if ( network_wait_for_playerinfo())
2462                                 network_read_sync_packet((netgame_info *)data,0);
2463  
2464                         NetSecurityFlag=0;
2465                         NetSecurityNum=0;
2466                          }
2467                 }
2468                 break;
2469
2470         case PID_PDATA: 
2471                 if ((Game_mode&GM_NETWORK) && ((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) || Network_status==NETSTAT_WAITING)) { 
2472                         network_process_pdata((char *)data);
2473                 }
2474                 break;
2475    case PID_NAKED_PDATA:
2476                 if ((Game_mode&GM_NETWORK) && ((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) || Network_status==NETSTAT_WAITING)) 
2477                         network_process_naked_pdata((char *)data,length);
2478            break;
2479
2480         case PID_OBJECT_DATA:
2481                 if (Network_status == NETSTAT_WAITING) 
2482                         network_read_object_packet(data);
2483                 break;
2484         case PID_ENDLEVEL:
2485                 if ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))
2486                         network_read_endlevel_packet(data);
2487                 else
2488                         mprintf((0, "Junked endlevel packet.\n"));
2489                 break;
2490         case PID_ENDLEVEL_SHORT:
2491                 if ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))
2492                         network_read_endlevel_short_packet(data);
2493                 else
2494                         mprintf((0, "Junked short endlevel packet!\n"));
2495                 break;
2496
2497         case PID_GAME_UPDATE:
2498                 mprintf ((0,"Got a GAME_UPDATE!\n"));
2499                         
2500                 if (Network_status==NETSTAT_PLAYING)
2501                  {
2502 #ifndef MACINTOSH
2503                         memcpy((ubyte *)&TempNetInfo, data, sizeof(lite_info) );
2504 #else
2505                         if (Network_game_type == IPX_GAME)
2506                                 receive_netgame_packet(data, &TempNetInfo, 1);
2507                         else
2508                                 memcpy((ubyte *)&TempNetInfo, data, sizeof(lite_info) );
2509 #endif
2510                   if (TempNetInfo.Security==Netgame.Security)
2511                          memcpy (&Netgame,(ubyte *)&TempNetInfo,sizeof(lite_info));
2512                  }
2513                 if (Game_mode & GM_TEAM)
2514                  {
2515                         int i;
2516
2517                         for (i=0;i<N_players;i++)
2518                          if (Players[i].connected)
2519                         multi_reset_object_texture (&Objects[Players[i].objnum]);
2520                     reset_cockpit();
2521                  }
2522            break;
2523    case PID_PING_SEND:
2524                 network_ping (PID_PING_RETURN,data[1]);
2525                 break;
2526    case PID_PING_RETURN:
2527                 network_handle_ping_return(data[1]);  // data[1] is player who told us of their ping time
2528                 break;
2529    case PID_NAMES_RETURN:
2530                 if (Network_status==NETSTAT_BROWSING && NamesInfoSecurity!=-1)
2531                   network_process_names_return (data);
2532                 break;
2533         case PID_GAME_PLAYERS:
2534                 // Someone wants a list of players in this game
2535
2536            if (length != SEQUENCE_PACKET_SIZE)
2537                  {
2538                   mprintf ((0,"WARNING! Recieved invalid size for PID_GAME_PLAYERS\n"));
2539                   return;
2540                  }
2541                         
2542                 mprintf((0, "Got a PID_GAME_PLAYERS!\n"));
2543                 if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
2544                         if (network_i_am_master() && their->Security==Netgame.Security)
2545                                 network_send_player_names(their);
2546                 break;
2547
2548         default:
2549                 mprintf((0, "Ignoring invalid packet type.\n"));
2550                 Int3(); // Invalid network packet type, see ROB
2551            break;
2552         }
2553 }
2554
2555 #ifndef NDEBUG
2556 void dump_segments()
2557 {
2558         FILE * fp;
2559
2560         fp = fopen( "TEST.DMP", "wb" );
2561         fwrite( Segments, sizeof(segment)*(Highest_segment_index+1),1, fp );    
2562         fclose(fp);
2563         mprintf( (0, "SS=%d\n", sizeof(segment) ));
2564 }
2565 #endif
2566
2567
2568 void
2569 network_read_endlevel_packet( ubyte *data )
2570 {
2571         // Special packet for end of level syncing
2572 #ifdef MACINTOSH
2573         int i, j;
2574 #endif
2575         int playernum;
2576         endlevel_info *end;     
2577
2578         end = (endlevel_info *)data;
2579 #ifdef MACINTOSH
2580         for (i = 0; i < MAX_PLAYERS; i++)
2581                 for (j = 0; j < MAX_PLAYERS; j++)
2582                         end->kill_matrix[i][j] = INTEL_SHORT(end->kill_matrix[i][j]);
2583         end->kills = INTEL_SHORT(end->kills);
2584         end->killed = INTEL_SHORT(end->killed);
2585 #endif
2586
2587         playernum = end->player_num;
2588         
2589         Assert(playernum != Player_num);
2590     
2591         if (playernum>=N_players)
2592          {              
2593                 Int3(); // weird, but it an happen in a coop restore game
2594                 return; // if it happens in a coop restore, don't worry about it
2595          }
2596
2597         if ((Network_status == NETSTAT_PLAYING) && (end->connected != 0))
2598                 return; // Only accept disconnect packets if we're not out of the level yet
2599
2600         Players[playernum].connected = end->connected;
2601         memcpy(&kill_matrix[playernum][0], end->kill_matrix, MAX_PLAYERS*sizeof(short));
2602         Players[playernum].net_kills_total = end->kills;
2603         Players[playernum].net_killed_total = end->killed;
2604
2605         if ((Players[playernum].connected == 1) && (end->seconds_left < Countdown_seconds_left))
2606                 Countdown_seconds_left = end->seconds_left;
2607
2608         LastPacketTime[playernum] = timer_get_approx_seconds();
2609
2610 //      mprintf((0, "Got endlevel packet from player %d.\n", playernum));
2611 }
2612
2613 void
2614 network_read_endlevel_short_packet( ubyte *data )
2615 {
2616         // Special packet for end of level syncing
2617
2618         int playernum;
2619         endlevel_info_short *end;       
2620
2621         end = (endlevel_info_short *)data;
2622
2623         playernum = end->player_num;
2624         
2625         Assert(playernum != Player_num);
2626     
2627         if (playernum>=N_players)
2628          {              
2629                 Int3(); // weird, but it can happen in a coop restore game
2630                 return; // if it happens in a coop restore, don't worry about it
2631          }
2632
2633         if ((Network_status == NETSTAT_PLAYING) && (end->connected != 0))
2634          {
2635                 //mprintf ((0,"Returning early for short_endlevel\n"));
2636                 return; // Only accept disconnect packets if we're not out of the level yet
2637          }
2638
2639         Players[playernum].connected = end->connected;
2640
2641         if ((Players[playernum].connected == 1) && (end->seconds_left < Countdown_seconds_left))
2642                 Countdown_seconds_left = end->seconds_left;
2643
2644         LastPacketTime[playernum] = timer_get_approx_seconds();
2645 }
2646
2647
2648 void
2649 network_pack_objects(void)
2650 {
2651         // Switching modes, pack the object array
2652
2653         special_reset_objects();
2654 }                               
2655
2656 int
2657 network_verify_objects(int remote, int local)
2658 {
2659         int i;
2660         int nplayers, got_controlcen=0;
2661
2662    mprintf ((0,"NETWORK:remote=%d local=%d\n",remote,local));
2663
2664         if ((remote-local) > 10)
2665                 return(-1);
2666
2667         if (Game_mode & GM_MULTI_ROBOTS)
2668                 got_controlcen = 1;
2669
2670         nplayers = 0;
2671
2672         for (i = 0; i <= Highest_object_index; i++)
2673         {
2674                 if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST))
2675                         nplayers++;
2676                 if (Objects[i].type == OBJ_CNTRLCEN)
2677                         got_controlcen=1;
2678         }
2679
2680     if (got_controlcen && (MaxNumNetPlayers<=nplayers))
2681                 return(0);
2682
2683         return(1);
2684 }
2685         
2686 void
2687 network_read_object_packet( ubyte *data )
2688 {
2689         // Object from another net player we need to sync with
2690
2691         short objnum, remote_objnum;
2692         byte obj_owner;
2693         int segnum, i;
2694         object *obj;
2695
2696         static int my_pnum = 0;
2697         static int mode = 0;
2698         static int object_count = 0;
2699         static int frame_num = 0;
2700         int nobj = data[1];
2701         int loc = 3;
2702         int remote_frame_num = data[2];
2703         
2704         frame_num++;
2705
2706 //      mprintf((0, "Object packet %d (remote #%d) contains %d objects.\n", frame_num, remote_frame_num, nobj));
2707
2708         for (i = 0; i < nobj; i++)
2709         {
2710                 objnum = INTEL_SHORT( *(short *)(data+loc) );                   loc += 2;
2711                 obj_owner = data[loc];                                                                  loc += 1;
2712                 remote_objnum = INTEL_SHORT( *(short *)(data+loc) );    loc += 2;
2713
2714                 if (objnum == -1) 
2715                 {
2716                         // Clear object array
2717                         mprintf((0, "Clearing object array.\n"));
2718
2719                         init_objects();
2720                         Network_rejoined = 1;
2721                         my_pnum = obj_owner;
2722                         change_playernum_to(my_pnum);
2723                         mode = 1;
2724                         object_count = 0;
2725                         frame_num = 1;
2726                 }
2727                 else if (objnum == -2)
2728                 {
2729                         // Special debug checksum marker for entire send
2730                         if (mode == 1)
2731                         {
2732                                 network_pack_objects();
2733                                 mode = 0;
2734                         }
2735                         mprintf((0, "Objnum -2 found in frame local %d remote %d.\n", frame_num, remote_frame_num));
2736                         mprintf((0, "Got %d objects, expected %d.\n", object_count, remote_objnum));
2737                         if (remote_objnum != object_count) {
2738                                 Int3();
2739                         }
2740                         if (network_verify_objects(remote_objnum, object_count))
2741                         {
2742                                 // Failed to sync up 
2743                                 nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED);
2744                                 Network_status = NETSTAT_MENU;                          
2745                                 return;
2746                         }
2747                         frame_num = 0;
2748                 }
2749                 else 
2750                 {
2751                         if (frame_num != remote_frame_num)
2752                                 Int3();
2753                         mprintf ((0,"Got a type 3 object packet!\n"));
2754                         object_count++;
2755                         if ((obj_owner == my_pnum) || (obj_owner == -1)) 
2756                         {
2757                                 if (mode != 1)
2758                                         Int3(); // SEE ROB
2759                                 objnum = remote_objnum;
2760                                 //if (objnum > Highest_object_index)
2761                                 //{
2762                                 //      Highest_object_index = objnum;
2763                                 //      num_objects = Highest_object_index+1;
2764                                 //}
2765                         }
2766                         else {
2767                                 if (mode == 1)
2768                                 {
2769                                         network_pack_objects();
2770                                         mode = 0;
2771                                 }
2772                                 objnum = obj_allocate();
2773                         }
2774                         if (objnum != -1) {
2775                                 obj = &Objects[objnum];
2776                                 if (obj->segnum != -1)
2777                                         obj_unlink(objnum);
2778                                 Assert(obj->segnum == -1);
2779                                 Assert(objnum < MAX_OBJECTS);
2780                                 memcpy(obj,data+loc,sizeof(object));            loc += sizeof(object);
2781 #ifdef MACINTOSH
2782                                 if (Network_game_type == IPX_GAME)
2783                                         swap_object(obj);
2784 #endif
2785                                 segnum = obj->segnum;
2786                                 obj->next = obj->prev = obj->segnum = -1;
2787                                 obj->attached_obj = -1;
2788                                 if (segnum > -1)
2789                                         obj_link(obj-Objects,segnum);
2790                                 if (obj_owner == my_pnum) 
2791                                         map_objnum_local_to_local(objnum);
2792                                 else if (obj_owner != -1)
2793                                         map_objnum_local_to_remote(objnum, remote_objnum, obj_owner);
2794                                 else
2795                                         object_owner[objnum] = -1;
2796                         }
2797                 } // For a standard onbject
2798         } // For each object in packet
2799 }
2800         
2801 void network_sync_poll( int nitems, newmenu_item * menus, int * key, int citem )
2802 {
2803         // Polling loop waiting for sync packet to start game
2804
2805         static fix t1 = 0;
2806
2807         menus = menus;
2808         citem = citem;
2809         nitems = nitems;
2810
2811         network_listen();
2812
2813         if (Network_status != NETSTAT_WAITING)  // Status changed to playing, exit the menu
2814                 *key = -2;
2815
2816         if (!Network_rejoined && (timer_get_approx_seconds() > t1+F1_0*2))
2817         {
2818                 int i;
2819
2820                 // Poll time expired, re-send request
2821                 
2822                 t1 = timer_get_approx_seconds();
2823
2824                 mprintf((0, "Re-sending join request.\n"));
2825                 i = network_send_request();
2826                 if (i < 0)
2827                         *key = -2;
2828         }
2829 }
2830
2831 void network_start_poll( int nitems, newmenu_item * menus, int * key, int citem )
2832 {
2833         int i,n,nm;
2834
2835         key=key;
2836         citem=citem;
2837
2838         Assert(Network_status == NETSTAT_STARTING);
2839
2840         if (!menus[0].value) {
2841                         menus[0].value = 1;
2842                         menus[0].redraw = 1;
2843         }
2844
2845         for (i=1; i<nitems; i++ )       {
2846                 if ( (i>= N_players) && (menus[i].value) )      {
2847                         menus[i].value = 0;
2848                         menus[i].redraw = 1;
2849                 }
2850         }
2851
2852         nm = 0;
2853         for (i=0; i<nitems; i++ )       {
2854                 if ( menus[i].value )   {
2855                         nm++;
2856                         if ( nm > N_players )   {
2857                                 menus[i].value = 0;
2858                                 menus[i].redraw = 1;
2859                         }
2860                 }
2861         }
2862
2863         if ( nm > MaxNumNetPlayers )    {
2864                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
2865                 // Turn off the last player highlighted
2866                 for (i = N_players; i > 0; i--)
2867                         if (menus[i].value == 1) 
2868                         {
2869                                 menus[i].value = 0;
2870                                 menus[i].redraw = 1;
2871                                 break;
2872                         }
2873         }
2874
2875 //       if (nitems > MAX_PLAYERS ) return; 
2876         
2877         n = Netgame.numplayers;
2878         network_listen();
2879
2880         if (n < Netgame.numplayers )    
2881         {
2882                 digi_play_sample (SOUND_HUD_MESSAGE,F1_0);
2883
2884       mprintf ((0,"More players are printed!"));
2885                 if (args_find("-norankings"))
2886               sprintf( menus[N_players-1].text, "%d. %-20s", N_players,NetPlayers.players[N_players-1].callsign );
2887                 else
2888               sprintf( menus[N_players-1].text, "%d. %s%-20s", N_players, RankStrings[NetPlayers.players[N_players-1].rank],NetPlayers.players[N_players-1].callsign );
2889
2890                 menus[N_players-1].redraw = 1;
2891                 if (N_players <= MaxNumNetPlayers)
2892                 {
2893                         menus[N_players-1].value = 1;
2894                 }
2895         } 
2896         else if ( n > Netgame.numplayers )      
2897         {
2898                 // One got removed...
2899
2900       digi_play_sample (SOUND_HUD_KILL,F1_0);
2901   
2902                 for (i=0; i<N_players; i++ )    
2903                 {
2904          
2905          if (args_find("-norankings"))  
2906                  sprintf( menus[i].text, "%d. %-20s", i+1, NetPlayers.players[i].callsign );
2907          else
2908                  sprintf( menus[i].text, "%d. %s%-20s", i+1, RankStrings[NetPlayers.players[i].rank],NetPlayers.players[i].callsign );
2909                         if (i < MaxNumNetPlayers)
2910                                 menus[i].value = 1;
2911                         else
2912                                 menus[i].value = 0;
2913                         menus[i].redraw = 1;
2914                 }
2915                 for (i=N_players; i<n; i++ )    
2916                 {
2917                         sprintf( menus[i].text, "%d. ", i+1 );          // Clear out the deleted entries...
2918                         menus[i].value = 0;
2919                         menus[i].redraw = 1;
2920                 }
2921    }
2922 }
2923
2924 int opt_cinvul, opt_team_anarchy, opt_coop, opt_show_on_map, opt_closed,opt_maxnet;
2925 int last_cinvul=0,last_maxnet,opt_team_hoard;
2926 int opt_refuse,opt_capture;
2927
2928 void network_game_param_poll( int nitems, newmenu_item * menus, int * key, int citem )
2929 {
2930         static oldmaxnet=0;
2931
2932         if (((HoardEquipped() && menus[opt_team_hoard].value) || (menus[opt_team_anarchy].value || menus[opt_capture].value)) && !menus[opt_closed].value && !menus[opt_refuse].value) { 
2933                 menus[opt_refuse].value = 1;
2934                 menus[opt_refuse].redraw = 1;
2935                 menus[opt_refuse-1].value = 0;
2936                 menus[opt_refuse-1].redraw = 1;
2937                 menus[opt_refuse-2].value = 0;
2938                 menus[opt_refuse-2].redraw = 1;
2939         }
2940
2941         #ifndef MACINTOSH
2942         if (menus[opt_coop].value)
2943         #else
2944         if ( (menus[opt_coop].value) || ((Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) && (menus[opt_coop-1].value)) )
2945         #endif
2946         {
2947                 oldmaxnet=1;
2948
2949                 if (menus[opt_maxnet].value>2) 
2950                 {
2951                     menus[opt_maxnet].value=2;
2952                     menus[opt_maxnet].redraw=1;
2953                 }
2954
2955                 if (menus[opt_maxnet].max_value>2)
2956                 {
2957                     menus[opt_maxnet].max_value=2;
2958                     menus[opt_maxnet].redraw=1;
2959                 }
2960
2961                 #ifdef MACINTOSH
2962                 if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
2963                         if (menus[opt_maxnet].value > 0) {
2964                             menus[opt_maxnet].value=0;
2965                             menus[opt_maxnet].redraw=1;
2966                         }
2967                         if (menus[opt_maxnet].max_value > 0) {
2968                                 menus[opt_maxnet].max_value=0;
2969                                 menus[opt_maxnet].redraw=1;
2970                         }
2971                 }
2972                 #endif
2973
2974              if (!Netgame.game_flags & NETGAME_FLAG_SHOW_MAP) 
2975                         Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP;
2976
2977                 if (Netgame.PlayTimeAllowed || Netgame.KillGoal)
2978                 {
2979                     Netgame.PlayTimeAllowed=0;
2980                     Netgame.KillGoal=0;
2981                 }
2982
2983         }
2984         else // if !Coop game
2985     {
2986                 if (oldmaxnet)
2987                 {
2988                     oldmaxnet=0;
2989                         menus[opt_maxnet].value=6;
2990                         menus[opt_maxnet].max_value=6;
2991
2992                     #ifdef MACINTOSH
2993                         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
2994                                 menus[opt_maxnet].value=1;
2995                                 menus[opt_maxnet].max_value=1;
2996                         }
2997                         #endif
2998                           
2999                 }
3000         }         
3001
3002     if ( last_maxnet != menus[opt_maxnet].value )   
3003         {
3004                 sprintf( menus[opt_maxnet].text, "Maximum players: %d", menus[opt_maxnet].value+2 );
3005                 last_maxnet = menus[opt_maxnet].value;
3006                 menus[opt_maxnet].redraw = 1;
3007         }               
3008  }
3009
3010 int netgame_difficulty;
3011
3012 int network_get_game_params( char * game_name, int *mode, int *game_flags, int *level )
3013 {
3014         int i;
3015    int opt, opt_name, opt_level, opt_mode,opt_moreopts;
3016         newmenu_item m[20];
3017         char name[NETGAME_NAME_LEN+1];
3018         char slevel[5];
3019         char level_text[32];
3020    char srmaxnet[50];
3021
3022         int new_mission_num;
3023         int anarchy_only;
3024             
3025    *game_flags=*game_flags;
3026
3027    SetAllAllowablesTo (1);
3028    NamesInfoSecurity=-1;
3029
3030         for (i=0;i<MAX_PLAYERS;i++)
3031          if (i!=Player_num)     
3032                 Players[i].callsign[0]=0;    
3033
3034         MaxNumNetPlayers=8;
3035    Netgame.KillGoal=0;
3036    Netgame.PlayTimeAllowed=0;
3037         Netgame.Allow_marker_view=1;
3038         netgame_difficulty=Player_default_difficulty;
3039
3040         new_mission_num = multi_choose_mission(&anarchy_only);
3041
3042         if (new_mission_num < 0)
3043                 return -1;
3044
3045    if (!(args_find ("-packets") && args_find ("-shortpackets")))
3046            if (!network_choose_connect ())
3047                         return -1;
3048
3049         #ifdef MACINTOSH
3050         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) )
3051                 MaxNumNetPlayers = 3;
3052         #endif
3053         
3054         strcpy(Netgame.mission_name, Mission_list[new_mission_num].filename);
3055         strcpy(Netgame.mission_title, Mission_list[new_mission_num].mission_name);
3056         Netgame.control_invul_time = control_invul_time;
3057         
3058         sprintf( name, "%s%s", Players[Player_num].callsign, TXT_S_GAME );
3059         sprintf( slevel, "1" );
3060
3061         opt = 0;
3062         m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_DESCRIPTION; opt++;
3063
3064         opt_name = opt;
3065         m[opt].type = NM_TYPE_INPUT; m[opt].text = name; m[opt].text_len = NETGAME_NAME_LEN; opt++;
3066
3067         sprintf(level_text, "%s (1-%d)", TXT_LEVEL_, Last_level);
3068
3069 //      if (Last_secret_level < -1)
3070 //              sprintf(level_text+strlen(level_text)-1, ", S1-S%d)", -Last_secret_level);
3071 //      else if (Last_secret_level == -1)
3072 //              sprintf(level_text+strlen(level_text)-1, ", S1)");
3073
3074         Assert(strlen(level_text) < 32);
3075
3076         m[opt].type = NM_TYPE_TEXT; m[opt].text = level_text; opt++;
3077
3078         opt_level = opt;
3079         m[opt].type = NM_TYPE_INPUT; m[opt].text = slevel; m[opt].text_len=4; opt++;
3080 //      m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_OPTIONS; opt++;
3081         
3082         opt_mode = opt;
3083         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY; m[opt].value=1; m[opt].group=0; opt++;
3084         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++;
3085         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY_W_ROBOTS; m[opt].value=0; m[opt].group=0; opt++;
3086         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_COOPERATIVE; m[opt].value=0; m[opt].group=0; opt_coop=opt; opt++;
3087         m[opt].type = NM_TYPE_RADIO; m[opt].text = "Capture the flag"; m[opt].value=0; m[opt].group=0; opt_capture=opt; opt++;
3088    
3089         if (HoardEquipped())
3090         {
3091                 m[opt].type = NM_TYPE_RADIO; m[opt].text = "Hoard"; m[opt].value=0; m[opt].group=0; opt++;
3092                 m[opt].type = NM_TYPE_RADIO; m[opt].text = "Team Hoard"; m[opt].value=0; m[opt].group=0; opt_team_hoard=opt; opt++;
3093            m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++;
3094         } 
3095         else
3096          {  m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++; }
3097
3098         m[opt].type = NM_TYPE_RADIO; m[opt].text = "Open game"; m[opt].group=1; m[opt].value=0; opt++;
3099         opt_closed = opt;
3100         m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_CLOSED_GAME; m[opt].group=1; m[opt].value=0; opt++;
3101    opt_refuse = opt;
3102    m[opt].type = NM_TYPE_RADIO; m[opt].text = "Restricted Game              "; m[opt].group=1; m[opt].value=Netgame.RefusePlayers; opt++;
3103
3104 //      m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_IDS; m[opt].value=0; opt++;
3105
3106    opt_maxnet = opt;
3107    sprintf( srmaxnet, "Maximum players: %d", MaxNumNetPlayers);
3108    m[opt].type = NM_TYPE_SLIDER; m[opt].value=MaxNumNetPlayers-2; m[opt].text= srmaxnet; m[opt].min_value=0; 
3109    m[opt].max_value=MaxNumNetPlayers-2; opt++;
3110    last_maxnet=MaxNumNetPlayers-2;
3111
3112    opt_moreopts=opt;
3113    m[opt].type = NM_TYPE_MENU;  m[opt].text = "More options..."; opt++;
3114
3115         Assert(opt <= 20);
3116
3117 menu:
3118    ExtGameStatus=GAMESTAT_NETGAME_OPTIONS; 
3119         i = newmenu_do1( NULL, NULL, opt, m, network_game_param_poll, 1 );
3120                                                                         //TXT_NETGAME_SETUP
3121    if (i==opt_moreopts)
3122     {
3123      if ( m[opt_mode+3].value )
3124       Game_mode=GM_MULTI_COOP;
3125      network_more_game_options();
3126      Game_mode=0;
3127      goto menu;
3128     }
3129   Netgame.RefusePlayers=m[opt_refuse].value;
3130
3131
3132         if ( i > -1 )   {
3133                 int j;
3134                       
3135    MaxNumNetPlayers = m[opt_maxnet].value+2;
3136    Netgame.max_numplayers=MaxNumNetPlayers;
3137                                 
3138                 for (j = 0; j < num_active_games; j++)
3139                         if (!stricmp(Active_games[j].game_name, name))
3140                         {
3141                                 nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_DUPLICATE_NAME);
3142                                 goto menu;
3143                         }
3144
3145                 strcpy( game_name, name );
3146                 
3147
3148                 *level = atoi(slevel);
3149
3150                 if ((*level < 1) || (*level > Last_level))
3151                 {
3152                         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE );
3153                         sprintf(slevel, "1");
3154                         goto menu;
3155                 }
3156                 if ( m[opt_mode].value )
3157                         *mode = NETGAME_ANARCHY;
3158
3159 #ifdef SHAREWARE
3160                 else 
3161                 {
3162                         nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_REGISTERED_ONLY );
3163                         m[opt_mode+1].value = 0;
3164                         m[opt_mode+2].value = 0;
3165                         m[opt_mode+3].value = 0;
3166                    if (HoardEquipped())
3167                                 m[opt_mode+4].value = 0;
3168
3169                         m[opt_mode].value = 1;
3170                         goto menu;
3171                 }
3172 #else
3173                 else if (m[opt_mode+1].value) {
3174                         *mode = NETGAME_TEAM_ANARCHY;
3175                 }
3176                 else if (m[opt_capture].value)
3177                         *mode = NETGAME_CAPTURE_FLAG;
3178                 else if (HoardEquipped() && m[opt_capture+1].value)
3179                                 *mode = NETGAME_HOARD;
3180                 else if (HoardEquipped() && m[opt_capture+2].value)
3181                                 *mode = NETGAME_TEAM_HOARD;
3182                 else if (anarchy_only) {
3183                         nm_messagebox(NULL, 1, TXT_OK, TXT_ANARCHY_ONLY_MISSION);
3184                         m[opt_mode+2].value = 0;
3185                         m[opt_mode+3].value = 0;
3186                         m[opt_mode].value = 1;
3187                         goto menu;
3188                 }               
3189                 else if ( m[opt_mode+2].value ) 
3190                         *mode = NETGAME_ROBOT_ANARCHY;
3191                 else if ( m[opt_mode+3].value ) 
3192                         *mode = NETGAME_COOPERATIVE;
3193                 else Int3(); // Invalid mode -- see Rob
3194 #endif
3195                 if (m[opt_closed].value)
3196                         Netgame.game_flags |= NETGAME_FLAG_CLOSED;
3197       
3198         }
3199
3200         return i;
3201 }
3202
3203 void
3204 network_set_game_mode(int gamemode)
3205 {
3206         Show_kill_list = 1;
3207
3208         if ( gamemode == NETGAME_ANARCHY )
3209                 Game_mode = GM_NETWORK;
3210         else if ( gamemode == NETGAME_ROBOT_ANARCHY )
3211                 Game_mode = GM_NETWORK | GM_MULTI_ROBOTS;
3212         else if ( gamemode == NETGAME_COOPERATIVE ) 
3213                 Game_mode = GM_NETWORK | GM_MULTI_COOP | GM_MULTI_ROBOTS;
3214         else if (gamemode == NETGAME_CAPTURE_FLAG)
3215                 {
3216                  Game_mode = GM_NETWORK | GM_TEAM | GM_CAPTURE;
3217                  Show_kill_list=3;
3218                 }
3219
3220         else if (HoardEquipped() && gamemode == NETGAME_HOARD)
3221                  Game_mode = GM_NETWORK | GM_HOARD;
3222         else if (HoardEquipped() && gamemode == NETGAME_TEAM_HOARD)
3223                  {
3224                   Game_mode = GM_NETWORK | GM_HOARD | GM_TEAM;
3225                   Show_kill_list=3;
3226                  }
3227         else if ( gamemode == NETGAME_TEAM_ANARCHY )
3228         {
3229                 Game_mode = GM_NETWORK | GM_TEAM;
3230                 Show_kill_list = 3;
3231         }
3232         else
3233                 Int3();
3234
3235 #if 0
3236 #ifdef MACINTOSH                        // minimize players on localtalk games
3237         if ( (Network_game_type == APPLETALK_GAME) && (Network_appletalk_type == LOCALTALK_TYPE) ) {
3238                 if (Game_mode & GM_MULTI_ROBOTS)
3239                         MaxNumNetPlayers = 2;
3240                 else
3241                         MaxNumNetPlayers = 3;
3242         } else {
3243                 if (Game_mode & GM_MULTI_COOP)
3244                         MaxNumNetPlayers = 4;
3245                 else
3246                         MaxNumNetPlayers = 8;
3247         }
3248 #endif
3249 #endif
3250
3251 }
3252
3253 int
3254 network_find_game(void)
3255 {
3256         // Find out whether or not there is space left on this socket
3257
3258         fix t1;
3259
3260         Network_status = NETSTAT_BROWSING;
3261
3262         num_active_games = 0;
3263
3264         show_boxed_message(TXT_WAIT);
3265
3266         network_send_game_list_request();
3267         t1 = timer_get_approx_seconds() + F1_0*3;
3268
3269         while (timer_get_approx_seconds() < t1) // Wait 3 seconds for replies
3270                 network_listen();
3271
3272         clear_boxed_message();
3273
3274 //      mprintf((0, "%s %d %s\n", TXT_FOUND, num_active_games, TXT_ACTIVE_GAMES));
3275
3276         if (num_active_games < MAX_ACTIVE_NETGAMES)
3277                 return 0;
3278         return 1;
3279 }
3280         
3281 void network_read_sync_packet( netgame_info * sp, int rsinit)
3282 {       
3283 #ifdef MACINTOSH
3284         netgame_info tmp_info;
3285 #endif
3286
3287         int i, j;
3288         char temp_callsign[CALLSIGN_LEN+1];
3289
3290 #ifdef MACINTOSH
3291         if ( (Network_game_type == IPX_GAME) && (sp != &Netgame) ) {                            // for macintosh -- get the values unpacked to our structure format
3292                 receive_netgame_packet((ubyte *)sp, &tmp_info, 0);
3293                 sp = &tmp_info;
3294         }
3295 #endif
3296
3297    if (rsinit)
3298      TempPlayersInfo=&NetPlayers;
3299         
3300         // This function is now called by all people entering the netgame.
3301
3302         // mprintf( (0, "%s %d\n", TXT_STARTING_NETGAME, sp->levelnum ));
3303
3304         if (sp != &Netgame)
3305          {
3306           memcpy( &Netgame, sp, sizeof(netgame_info) );
3307           memcpy (&NetPlayers,TempPlayersInfo,sizeof (AllNetPlayers_info));
3308          }
3309
3310         N_players = sp->numplayers;
3311         Difficulty_level = sp->difficulty;
3312         Network_status = sp->game_status;
3313
3314    //Assert(Function_mode != FMODE_GAME);
3315
3316         // New code, 11/27
3317
3318         mprintf((1, "Netgame.checksum = %d, calculated checksum = %d.\n", Netgame.segments_checksum, my_segments_checksum));
3319
3320         if (Netgame.segments_checksum != my_segments_checksum)
3321         {
3322                 Network_status = NETSTAT_MENU;
3323                 nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NETLEVEL_NMATCH);
3324 #ifdef RELEASE
3325                 return;
3326 #endif
3327         }
3328
3329         // Discover my player number
3330
3331         memcpy(temp_callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
3332         
3333         Player_num = -1;
3334
3335         for (i=0; i<MAX_NUM_NET_PLAYERS; i++ )  {
3336                 Players[i].net_kills_total = 0;
3337 //              Players[i].net_killed_total = 0;
3338         }
3339
3340         for (i=0; i<N_players; i++ )    {
3341                 if (Network_game_type == IPX_GAME) {
3342                         if ( (!memcmp( TempPlayersInfo->players[i].network.ipx.node, My_Seq.player.network.ipx.node, 6 )) && (!stricmp( TempPlayersInfo->players[i].callsign, temp_callsign)) ) {
3343                                 if (Player_num!=-1) {
3344                                         Int3(); // Hey, we've found ourselves twice
3345                                         mprintf ((0,"Hey, we've found ourselves twice!\n"));
3346                                         Network_status = NETSTAT_MENU;
3347                                         return; 
3348                                 }
3349                                 change_playernum_to(i);
3350                         }
3351                 } else {
3352                         if ( (TempPlayersInfo->players[i].network.appletalk.node == My_Seq.player.network.appletalk.node) && (!stricmp( TempPlayersInfo->players[i].callsign, temp_callsign)) ) {
3353                                 if (Player_num!=-1) {
3354                                         Int3(); // Hey, we've found ourselves twice
3355                                         Network_status = NETSTAT_MENU;
3356                                         return; 
3357                                 }
3358                                 change_playernum_to(i);
3359                         }
3360                 }
3361                 memcpy( Players[i].callsign, TempPlayersInfo->players[i].callsign, CALLSIGN_LEN+1 );
3362
3363                 if (Network_game_type == IPX_GAME) {
3364                         if ( (*(uint *)TempPlayersInfo->players[i].network.ipx.server) != 0 )
3365                                 ipx_get_local_target( TempPlayersInfo->players[i].network.ipx.server, TempPlayersInfo->players[i].network.ipx.node, Players[i].net_address );
3366                         else
3367                                 memcpy( Players[i].net_address, TempPlayersInfo->players[i].network.ipx.node, 6 );
3368                 }
3369                                 
3370                 Players[i].n_packets_got=0;                             // How many packets we got from them
3371                 Players[i].n_packets_sent=0;                            // How many packets we sent to them
3372                 Players[i].connected = TempPlayersInfo->players[i].connected;
3373                 Players[i].net_kills_total = sp->player_kills[i];
3374                 Players[i].net_killed_total = sp->killed[i];
3375                 if ((Network_rejoined) || (i != Player_num))
3376                         Players[i].score = sp->player_score[i];
3377                 for (j = 0; j < MAX_NUM_NET_PLAYERS; j++)
3378                 {
3379                         kill_matrix[i][j] = sp->kills[i][j];
3380                 }
3381         }
3382
3383         if ( Player_num < 0 )   {
3384                 mprintf ((0,"Bad Player_num, resetting to NETSTAT_MENU!\n"));
3385                 Network_status = NETSTAT_MENU;
3386                 return;
3387         }
3388
3389         if (Network_rejoined) 
3390                 for (i=0; i<N_players;i++)
3391                         Players[i].net_killed_total = sp->killed[i];
3392
3393         if (Network_rejoined) {
3394                 network_process_monitor_vector(sp->monitor_vector);
3395                 Players[Player_num].time_level = sp->level_time;
3396         }
3397
3398         team_kills[0] = sp->team_kills[0];
3399         team_kills[1] = sp->team_kills[1];
3400         
3401         Players[Player_num].connected = 1;
3402    NetPlayers.players[Player_num].connected = 1;
3403    NetPlayers.players[Player_num].rank=GetMyNetRanking();
3404
3405         if (!Network_rejoined)
3406                 for (i=0; i<NumNetPlayerPositions; i++) {
3407                         Objects[Players[i].objnum].pos = Player_init[Netgame.locations[i]].pos;
3408                         Objects[Players[i].objnum].orient = Player_init[Netgame.locations[i]].orient;
3409                         obj_relink(Players[i].objnum,Player_init[Netgame.locations[i]].segnum);
3410                 }
3411
3412         Objects[Players[Player_num].objnum].type = OBJ_PLAYER;
3413
3414    mprintf ((0,"Changing to NETSTAT_PLAYING!\n"));
3415         Network_status = NETSTAT_PLAYING;
3416         Function_mode = FMODE_GAME;
3417         multi_sort_kill_list();
3418
3419 }
3420
3421 void
3422 network_send_sync(void)
3423 {
3424         int i, j, np;
3425
3426         // Randomize their starting locations...
3427
3428         d_srand( timer_get_fixed_seconds() );
3429         for (i=0; i<NumNetPlayerPositions; i++ )        
3430         {
3431                 if (Players[i].connected)
3432                         Players[i].connected = 1; // Get rid of endlevel connect statuses
3433                 if (Game_mode & GM_MULTI_COOP)
3434                         Netgame.locations[i] = i;
3435                 else {
3436                         do 
3437                         {
3438                                 np = d_rand() % NumNetPlayerPositions;
3439                                 for (j=0; j<i; j++ )    
3440                                 {
3441                                         if (Netgame.locations[j]==np)   
3442                                         {
3443                                                 np =-1;
3444                                                 break;
3445                                         }
3446                                 }
3447                         } while (np<0);
3448                         // np is a location that is not used anywhere else..
3449                         Netgame.locations[i]=np;
3450 //                      mprintf((0, "Player %d starting in location %d\n" ,i ,np ));
3451                 }
3452         }
3453
3454         // Push current data into the sync packet
3455
3456         network_update_netgame();
3457         Netgame.game_status = NETSTAT_PLAYING;
3458         Netgame.type = PID_SYNC;
3459         Netgame.segments_checksum = my_segments_checksum;
3460
3461         for (i=0; i<N_players; i++ )    {
3462                 if ((!Players[i].connected) || (i == Player_num))
3463                         continue;
3464
3465                 if (Network_game_type == IPX_GAME) {
3466                 // Send several times, extras will be ignored
3467                         #ifndef MACINTOSH
3468                         ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3469                         ipx_send_internetwork_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3470                         #else
3471                         send_netgame_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, NULL, 0);
3472                         send_netplayers_packet(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node);
3473                         #endif
3474                 #ifdef MACINTOSH
3475                 } else {
3476                                 appletalk_send_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), NetPlayers.players[i].network.appletalk.node,
3477                                         NetPlayers.players[i].network.appletalk.net,
3478                                         NetPlayers.players[i].network.appletalk.socket);
3479                                 appletalk_send_packet_data( (ubyte *)&NetPlayers, sizeof(AllNetPlayers_info), NetPlayers.players[i].network.appletalk.node,
3480                                         NetPlayers.players[i].network.appletalk.net,
3481                                         NetPlayers.players[i].network.appletalk.socket);
3482                 #endif
3483                 }
3484
3485         }       
3486         network_read_sync_packet(&Netgame,1); // Read it myself, as if I had sent it
3487 }
3488
3489 int
3490 network_select_teams(void)
3491 {
3492 #ifndef SHAREWARE
3493         newmenu_item m[MAX_PLAYERS+4];
3494         int choice, opt, opt_team_b;
3495         ubyte team_vector = 0;
3496         char team_names[2][CALLSIGN_LEN+1];
3497         int i;
3498         int pnums[MAX_PLAYERS+2];
3499
3500         // One-time initialization
3501
3502         for (i = N_players/2; i < N_players; i++) // Put first half of players on team A
3503         {
3504                 team_vector |= (1 << i);
3505         }
3506
3507         sprintf(team_names[0], "%s", TXT_BLUE);
3508         sprintf(team_names[1], "%s", TXT_RED);
3509
3510         // Here comes da menu
3511 menu:
3512         m[0].type = NM_TYPE_INPUT; m[0].text = team_names[0]; m[0].text_len = CALLSIGN_LEN; 
3513
3514         opt = 1;
3515         for (i = 0; i < N_players; i++)
3516         {
3517                 if (!(team_vector & (1 << i)))
3518                 {
3519                         m[opt].type = NM_TYPE_MENU; m[opt].text = NetPlayers.players[i].callsign; pnums[opt] = i; opt++;
3520                 }
3521         }
3522         opt_team_b = opt;
3523         m[opt].type = NM_TYPE_INPUT; m[opt].text = team_names[1]; m[opt].text_len = CALLSIGN_LEN; opt++;
3524         for (i = 0; i < N_players; i++)
3525         {
3526                 if (team_vector & (1 << i))
3527                 {
3528                         m[opt].type = NM_TYPE_MENU; m[opt].text = NetPlayers.players[i].callsign; pnums[opt] = i; opt++;
3529                 }
3530         }
3531         m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++;
3532         m[opt].type = NM_TYPE_MENU; m[opt].text = TXT_ACCEPT; opt++;
3533
3534         Assert(opt <= MAX_PLAYERS+4);
3535         
3536         choice = newmenu_do(NULL, TXT_TEAM_SELECTION, opt, m, NULL);
3537
3538         if (choice == opt-1)
3539         {
3540                 if ((opt-2-opt_team_b < 2) || (opt_team_b == 1)) 
3541                 {
3542                         nm_messagebox(NULL, 1, TXT_OK, TXT_TEAM_MUST_ONE);
3543                         #ifdef RELEASE
3544                                 goto menu;
3545                         #endif
3546                 }
3547                 
3548                 Netgame.team_vector = team_vector;
3549                 strcpy(Netgame.team_name[0], team_names[0]);
3550                 strcpy(Netgame.team_name[1], team_names[1]);
3551                 return 1;
3552         }
3553
3554         else if ((choice > 0) && (choice < opt_team_b)) {
3555                 team_vector |= (1 << pnums[choice]);
3556         }
3557         else if ((choice > opt_team_b) && (choice < opt-2)) {
3558                 team_vector &= ~(1 << pnums[choice]);
3559         }
3560         else if (choice == -1)
3561                 return 0;
3562         goto menu;
3563 #else
3564         return 0;
3565 #endif
3566 }
3567
3568 int
3569 network_select_players(void)
3570 {
3571         int i, j;
3572    newmenu_item m[MAX_PLAYERS+4];
3573    char text[MAX_PLAYERS+4][45];
3574         char title[50];
3575         int save_nplayers;              //how may people would like to join
3576
3577         network_add_player( &My_Seq );
3578                 
3579         for (i=0; i< MAX_PLAYERS+4; i++ ) {
3580                 sprintf( text[i], "%d.  %-20s", i+1, "" );
3581                 m[i].type = NM_TYPE_CHECK; m[i].text = text[i]; m[i].value = 0;
3582         }
3583
3584         m[0].value = 1;                         // Assume server will play...
3585
3586    if (args_find("-norankings"))
3587                 sprintf( text[0], "%d. %-20s", 1, Players[Player_num].callsign );
3588         else
3589                 sprintf( text[0], "%d. %s%-20s", 1, RankStrings[NetPlayers.players[Player_num].rank],Players[Player_num].callsign );
3590
3591         sprintf( title, "%s %d %s", TXT_TEAM_SELECT, MaxNumNetPlayers, TXT_TEAM_PRESS_ENTER );
3592
3593 GetPlayersAgain:
3594    ExtGameStatus=GAMESTAT_NETGAME_PLAYER_SELECT;
3595         j=newmenu_do1( NULL, title, MAX_PLAYERS+4, m, network_start_poll, 1 );
3596
3597         save_nplayers = N_players;
3598
3599         if (j<0) 
3600         {
3601                 // Aborted!                                      
3602                 // Dump all players and go back to menu mode
3603
3604 abort:
3605                 for (i=1; i<save_nplayers; i++) {
3606                         if (Network_game_type == IPX_GAME)
3607                                 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, DUMP_ABORTED);
3608                         #ifdef MACINTOSH
3609                         else
3610                                 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, DUMP_ABORTED);
3611                         #endif
3612                 }
3613                         
3614
3615                 Netgame.numplayers = 0;
3616                 network_send_game_info(0); // Tell everyone we're bailing
3617
3618                 Network_status = NETSTAT_MENU;
3619                 return(0);
3620         }
3621        
3622         // Count number of players chosen
3623
3624         N_players = 0;
3625         for (i=0; i<save_nplayers; i++ )
3626         {
3627                 if (m[i].value) 
3628                         N_players++;
3629         }
3630         
3631         if ( N_players > Netgame.max_numplayers) {
3632                 #ifndef MACINTOSH
3633                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
3634                 #else
3635                 nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d netplayers for this game.", TXT_SORRY_ONLY, MaxNumNetPlayers );
3636                 #endif
3637                 N_players = save_nplayers;
3638                 goto GetPlayersAgain;
3639         }
3640
3641 #ifdef RELEASE
3642         if ( N_players < 2 )    {
3643                 nm_messagebox( TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_TWO );
3644                 N_players = save_nplayers;
3645                 goto GetPlayersAgain;
3646         }
3647 #endif
3648
3649 #ifdef RELEASE
3650         if ( (Netgame.gamemode == NETGAME_TEAM_ANARCHY ||
3651                    Netgame.gamemode == NETGAME_CAPTURE_FLAG || Netgame.gamemode == NETGAME_TEAM_HOARD) && (N_players < 2) ) {
3652                 nm_messagebox(TXT_ERROR, 1, TXT_OK, "You must select at least two\nplayers to start a team game" );
3653                 N_players = save_nplayers;
3654                 goto GetPlayersAgain;
3655         }
3656 #endif
3657
3658         // Remove players that aren't marked.
3659         N_players = 0;
3660         for (i=0; i<save_nplayers; i++ )        {
3661                 if (m[i].value) 
3662                 {
3663                         if (i > N_players)
3664                         {
3665                                 if (Network_game_type == IPX_GAME) {
3666                                         memcpy(NetPlayers.players[N_players].network.ipx.node, NetPlayers.players[i].network.ipx.node, 6);
3667                                         memcpy(NetPlayers.players[N_players].network.ipx.server, NetPlayers.players[i].network.ipx.server, 4);
3668                                 } else {
3669                                         NetPlayers.players[N_players].network.appletalk.node = NetPlayers.players[i].network.appletalk.node;
3670                                         NetPlayers.players[N_players].network.appletalk.net = NetPlayers.players[i].network.appletalk.net;
3671                                         NetPlayers.players[N_players].network.appletalk.socket = NetPlayers.players[i].network.appletalk.socket;
3672                                 }
3673                                 memcpy(NetPlayers.players[N_players].callsign, NetPlayers.players[i].callsign, CALLSIGN_LEN+1);
3674                                 NetPlayers.players[N_players].version_major=NetPlayers.players[i].version_major;
3675                                 NetPlayers.players[N_players].version_minor=NetPlayers.players[i].version_minor;
3676                                 NetPlayers.players[N_players].rank=NetPlayers.players[i].rank;
3677                                 ClipRank (&NetPlayers.players[N_players].rank);
3678                                 network_check_for_old_version(i);
3679                         }
3680                         Players[N_players].connected = 1;
3681                         N_players++;
3682                 }
3683                 else
3684                 {
3685                         if (Network_game_type == IPX_GAME)
3686                                 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, DUMP_DORK);
3687                         #ifdef MACINTOSH
3688                         else
3689                                 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, DUMP_DORK);
3690                         #endif
3691                 }
3692         }
3693
3694         for (i = N_players; i < MAX_NUM_NET_PLAYERS; i++) {
3695                 if (Network_game_type == IPX_GAME) {
3696                 memset(NetPlayers.players[i].network.ipx.node, 0, 6);
3697                 memset(NetPlayers.players[i].network.ipx.server, 0, 4);
3698             } else {
3699                 NetPlayers.players[i].network.appletalk.node = 0;
3700                 NetPlayers.players[i].network.appletalk.net = 0;
3701                 NetPlayers.players[i].network.appletalk.socket = 0;
3702             }
3703         memset(NetPlayers.players[i].callsign, 0, CALLSIGN_LEN+1);
3704                 NetPlayers.players[i].version_major=0;
3705                 NetPlayers.players[i].version_minor=0;
3706                 NetPlayers.players[i].rank=0;
3707         }
3708
3709    mprintf ((0,"Select teams: Game mode is %d\n",Netgame.gamemode));
3710
3711         if (Netgame.gamemode == NETGAME_TEAM_ANARCHY ||
3712             Netgame.gamemode == NETGAME_CAPTURE_FLAG ||
3713                  Netgame.gamemode == NETGAME_TEAM_HOARD)
3714                  if (!network_select_teams())
3715                         goto abort;
3716
3717         return(1); 
3718 }
3719
3720 void 
3721 network_start_game()
3722 {
3723         int i;
3724         char game_name[NETGAME_NAME_LEN+1];
3725         int chosen_game_mode, game_flags, level;
3726
3727         if (Network_game_type == IPX_GAME) {
3728
3729                 Assert( FRAME_INFO_SIZE < IPX_MAX_DATA_SIZE );
3730                 mprintf((0, "Using frame_info len %d, max %d.\n", FRAME_INFO_SIZE, IPX_MAX_DATA_SIZE));
3731                 
3732                 if ( !Network_active )
3733                 {
3734                         nm_messagebox(NULL, 1, TXT_OK, TXT_IPX_NOT_FOUND );
3735                         return;
3736                 }
3737         #ifdef MACINTOSH
3738         } else {
3739                 int err;
3740                 char buf[256];
3741
3742                 Assert( FRAME_INFO_SIZE < APPLETALK_MAX_DATA_SIZE );            
3743                 mprintf((0, "Using frame_info len %d, max %d.\n", sizeof(frame_info), APPLETALK_MAX_DATA_SIZE));
3744                 if (Appletalk_active <= 0) {
3745                         switch (Appletalk_active) {
3746                         case APPLETALK_NOT_OPEN:
3747                                 sprintf(buf, "Appletalk is not currently active.\nPlease enable AppleTalk from the\nChooser and restart Descent.");
3748                                 break;
3749                         case APPLETALK_BAD_LISTENER:
3750                                 sprintf(buf, "The Resource Fork of Descent appears damaged.\nPlease re-install Descent or contact\nMacPlay technical support.");
3751                                 break;
3752                         case APPLETALK_NO_LOCAL_ADDR:
3753                                 sprintf(buf, "Wow! Strange!\n\nNo Local Address.");
3754                                 break;
3755                         case APPLETALK_NO_SOCKET:
3756                                 sprintf(buf, "All AppleTalk sockets are in use.\nTry shutting down other network\napplications and restarting Descent.\n");
3757                                 break;
3758                         }
3759                         nm_messagebox(NULL, 1, TXT_OK, buf);
3760                         return;
3761                 }
3762                 strcpy(Network_zone_name, DEFAULT_ZONE_NAME);
3763         #endif
3764         }
3765
3766         network_init();
3767         change_playernum_to(0);
3768
3769         if (network_find_game())
3770         {
3771                 nm_messagebox(NULL, 1, TXT_OK, TXT_NET_FULL);
3772                 return;
3773         }
3774
3775         game_flags = 0;
3776         i = network_get_game_params( game_name, &chosen_game_mode, &game_flags, &level );
3777
3778         if (i<0) return;
3779
3780         N_players = 0;
3781
3782 // LoadLevel(level); Old, no longer used.
3783
3784         Netgame.difficulty = Difficulty_level;
3785         Netgame.gamemode = chosen_game_mode;
3786         Netgame.game_status = NETSTAT_STARTING;
3787         Netgame.numplayers = 0;
3788         Netgame.max_numplayers = MaxNumNetPlayers;
3789         Netgame.levelnum = level;
3790         Netgame.protocol_version = MULTI_PROTO_VERSION;
3791
3792         strcpy(Netgame.game_name, game_name);
3793         
3794         Network_status = NETSTAT_STARTING;
3795
3796         #ifdef MACINTOSH
3797         if (Network_game_type == APPLETALK_GAME) {
3798                 OSErr err;
3799                 fix t1;
3800                 int count = 0;
3801                 
3802                 show_boxed_message("Registering Netgame");
3803                 do {
3804                         err = appletalk_register_netgame( game_name, TickCount() );
3805                         t1 = timer_get_fixed_seconds() + F1_0;
3806                         while (timer_get_fixed_seconds() < t1) ;
3807                         count++;
3808                 } while ( (err == nbpDuplicate) && (count != MAX_REGISTER_TRIES) );
3809                 clear_boxed_message();
3810                 if ( (err == tooManyReqs) || (count == MAX_REGISTER_TRIES) ) {
3811                         nm_messagebox(NULL, 1, TXT_OK, "AppleTalk Network is too busy.\nPlease try again shortly.");
3812                         Game_mode = GM_GAME_OVER;
3813                         return;
3814                 }
3815         }
3816         #endif
3817
3818         network_set_game_mode(Netgame.gamemode);
3819
3820    d_srand( timer_get_fixed_seconds() );
3821    Netgame.Security=d_rand();  // For syncing Netgames with player packets
3822
3823         if(network_select_players())
3824         {
3825                 StartNewLevel(Netgame.levelnum, 0);
3826         }
3827         else
3828                 Game_mode = GM_GAME_OVER;
3829         
3830 }
3831
3832 void restart_net_searching(newmenu_item * m)
3833 {
3834         int i;
3835         N_players = 0;
3836         num_active_games = 0;
3837
3838         memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
3839
3840         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++)
3841         {
3842                 sprintf(m[i+2].text, "%d.                                                     ",i+1);
3843                 m[i+2].redraw = 1;
3844         }
3845   
3846    NamesInfoSecurity=-1;
3847         Network_games_changed = 1;      
3848 }
3849
3850 char *ModeLetters[]={"ANRCHY","TEAM","ROBO","COOP","FLAG","HOARD","TMHOARD"};
3851
3852 int NumActiveNetgames=0;
3853
3854 void network_join_poll( int nitems, newmenu_item * menus, int * key, int citem )
3855 {
3856         // Polling loop for Join Game menu
3857         static fix t1 = 0;
3858         int i, osocket,join_status,temp;
3859
3860         menus = menus;
3861         citem = citem;
3862         nitems = nitems;
3863         key = key;
3864
3865         if ( (Network_game_type == IPX_GAME) && Network_allow_socket_changes )      {
3866                 osocket = Network_socket;
3867         
3868                 if ( *key==KEY_PAGEDOWN )       { Network_socket--; *key = 0; }
3869                 if ( *key==KEY_PAGEUP )         { Network_socket++; *key = 0; }
3870         
3871                 if (Network_socket>99)
3872                  Network_socket=99;
3873            if (Network_socket<-99)
3874                  Network_socket=-99;    
3875         
3876                 if ( Network_socket+IPX_DEFAULT_SOCKET > 0x8000 )
3877                         Network_socket  = 0x8000 - IPX_DEFAULT_SOCKET;
3878         
3879                 if ( Network_socket+IPX_DEFAULT_SOCKET < 0 )
3880                         Network_socket  = IPX_DEFAULT_SOCKET;
3881         
3882                 if (Network_socket != osocket )         {
3883                         sprintf( menus[0].text, "\t%s %+d (PgUp/PgDn to change)", TXT_CURRENT_IPX_SOCKET, Network_socket );
3884                         menus[0].redraw = 1;
3885                         mprintf(( 0, "Changing to socket %d\n", Network_socket ));
3886                         network_listen();
3887                         mprintf ((0,"netgood 1!\n"));
3888                         ipx_change_default_socket( IPX_DEFAULT_SOCKET + Network_socket );
3889                         mprintf ((0,"netgood 2!\n"));
3890                         restart_net_searching(menus);
3891                         mprintf ((0,"netgood 3!\n"));
3892                         network_send_game_list_request();
3893                         mprintf ((0,"netgood 4!\n"));
3894                         return;
3895                 }
3896         }
3897
3898    // send a request for game info every 3 seconds
3899   
3900         if (Network_game_type == IPX_GAME) {  
3901                 if (timer_get_approx_seconds() > t1+F1_0*3) {
3902                         t1 = timer_get_approx_seconds();
3903                         network_send_game_list_request();
3904                 }
3905         #ifdef MACINTOSH
3906         } else if (timer_get_approx_seconds() > t1+F1_0*20) {
3907                 hide_cursor();
3908                 t1 = timer_get_approx_seconds();
3909                 restart_net_searching(menus);
3910                 show_boxed_message("Requesting list of Netgames");
3911                 network_send_game_list_request();
3912                 clear_boxed_message();
3913                 show_cursor();
3914         #endif
3915         }
3916    
3917    temp=num_active_games;
3918         
3919         network_listen();
3920
3921    NumActiveNetgames=num_active_games;
3922
3923    if (!Network_games_changed)
3924      return;
3925
3926    if (temp!=num_active_games)
3927            digi_play_sample (SOUND_HUD_MESSAGE,F1_0);
3928  
3929         Network_games_changed = 0;
3930    mprintf ((0,"JOIN POLL: I'm looking at %d games!\n",num_active_games));
3931
3932         // Copy the active games data into the menu options
3933         for (i = 0; i < num_active_games; i++)
3934         {
3935                 int game_status = Active_games[i].game_status;
3936       int j,x, k,tx,ty,ta,nplayers = 0;
3937       char levelname[8],MissName[25],GameName[25],thold[2];
3938       thold[1]=0;
3939
3940       // These next two loops protect against menu skewing
3941       // if missiontitle or gamename contain a tab
3942                  
3943       for (x=0,tx=0,k=0,j=0;j<15;j++)
3944         {
3945           if (Active_games[i].mission_title[j]=='\t')
3946             continue;
3947           thold[0]=Active_games[i].mission_title[j];
3948           gr_get_string_size (thold,&tx,&ty,&ta);
3949  
3950           if ((x+=tx)>=LHX(55))
3951             {
3952               MissName[k]=MissName[k+1]=MissName[k+2]='.';
3953               k+=3;
3954               break;
3955             }
3956           
3957           MissName[k++]=Active_games[i].mission_title[j];
3958         }
3959       MissName[k]=0;
3960
3961       for (x=0,tx=0,k=0,j=0;j<15;j++)
3962         {
3963           if (Active_games[i].game_name[j]=='\t')
3964             continue;
3965           thold[0]=Active_games[i].game_name[j];
3966           gr_get_string_size (thold,&tx,&ty,&ta);
3967
3968           if ((x+=tx)>=LHX(55))
3969             {
3970               GameName[k]=GameName[k+1]=GameName[k+2]='.';
3971               k+=3;
3972               break;
3973             }
3974           GameName[k++]=Active_games[i].game_name[j];
3975         }
3976       GameName[k]=0;
3977
3978            
3979       nplayers=Active_games[i].numconnected;
3980
3981                 if (Active_games[i].levelnum < 0)
3982                         sprintf(levelname, "S%d", -Active_games[i].levelnum);
3983                 else 
3984                         sprintf(levelname, "%d", Active_games[i].levelnum);
3985           
3986                 if (game_status == NETSTAT_STARTING) 
3987                 {
3988         sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
3989                  i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
3990                  Active_games[i].max_numplayers,MissName,levelname,"Forming");
3991                 }
3992                 else if (game_status == NETSTAT_PLAYING)
3993                 {
3994                  join_status=can_join_netgame(&Active_games[i],NULL);   
3995 //               mprintf ((0,"Joinstatus=%d\n",join_status));
3996                 
3997         if (join_status==1)
3998             sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
3999                      i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
4000                      Active_games[i].max_numplayers,MissName,levelname,"Open");
4001                         else if (join_status==2)
4002             sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
4003                      i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
4004                      Active_games[i].max_numplayers,MissName,levelname,"Full");
4005                         else if (join_status==3)
4006             sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
4007                      i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
4008                      Active_games[i].max_numplayers,MissName,levelname,"Restrict");
4009                         else
4010             sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
4011                      i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
4012                      Active_games[i].max_numplayers,MissName,levelname,"Closed");
4013
4014                 }
4015                 else
4016          sprintf (menus[i+2].text,"%d.\t%s \t%s \t  %d/%d \t%s \t %s \t%s",
4017                   i+1,GameName,ModeLetters[Active_games[i].gamemode],nplayers,
4018                   Active_games[i].max_numplayers,MissName,levelname,"Between");
4019                  
4020
4021       Assert(strlen(menus[i+2].text) < 100);
4022       menus[i+2].redraw = 1;
4023         }
4024
4025         for (i = num_active_games; i < MAX_ACTIVE_NETGAMES; i++)
4026         {
4027                 sprintf(menus[i+2].text, "%d.                                                     ",i+1);
4028                 menus[i+2].redraw = 1;
4029         }
4030 }
4031
4032 int
4033 network_wait_for_sync(void)
4034 {
4035         char text[60];
4036         newmenu_item m[2];
4037         int i, choice;
4038         
4039         Network_status = NETSTAT_WAITING;
4040
4041         m[0].type=NM_TYPE_TEXT; m[0].text = text;
4042         m[1].type=NM_TYPE_TEXT; m[1].text = TXT_NET_LEAVE;
4043         
4044         i = network_send_request();
4045
4046         if (i < 0)
4047                 return(-1);
4048
4049         sprintf( m[0].text, "%s\n'%s' %s", TXT_NET_WAITING, NetPlayers.players[i].callsign, TXT_NET_TO_ENTER );
4050
4051 menu:   
4052         choice=newmenu_do( NULL, TXT_WAIT, 2, m, network_sync_poll );
4053
4054         if (choice > -1)
4055                 goto menu;
4056
4057         if (Network_status != NETSTAT_PLAYING)  
4058         {
4059                 sequence_packet me;
4060
4061 //              if (Network_status == NETSTAT_ENDLEVEL)
4062 //              {
4063 //                      network_send_endlevel_packet(0);
4064 //                      longjmp(LeaveGame, 0);
4065 //              }               
4066
4067                 mprintf((0, "Aborting join.\n"));
4068                 me.type = PID_QUIT_JOINING;
4069                 memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
4070                 if (Network_game_type == IPX_GAME) {
4071                         memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 );
4072                         memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 );
4073                         #ifndef MACINTOSH
4074                         ipx_send_internetwork_packet_data( (ubyte *)&me, sizeof(sequence_packet), NetPlayers.players[0].network.ipx.server, NetPlayers.players[0].network.ipx.node );
4075                         #else
4076                         send_sequence_packet(me, NetPlayers.players[0].network.ipx.server, NetPlayers.players[0].network.ipx.node, NULL);
4077                         #endif
4078                 #ifdef MACINTOSH
4079                 } else {
4080                         me.player.network.appletalk.node = appletalk_get_my_node();
4081                         me.player.network.appletalk.net = appletalk_get_my_net();
4082                         me.player.network.appletalk.socket = appletalk_get_my_socket();
4083                 #endif
4084                 }
4085                 N_players = 0;
4086                 Function_mode = FMODE_MENU;
4087                 Game_mode = GM_GAME_OVER;
4088                 return(-1);     // they cancelled               
4089         }
4090         return(0);
4091 }
4092
4093 void 
4094 network_request_poll( int nitems, newmenu_item * menus, int * key, int citem )
4095 {
4096         // Polling loop for waiting-for-requests menu
4097
4098         int i = 0;
4099         int num_ready = 0;
4100
4101         menus = menus;
4102         citem = citem;
4103         nitems = nitems;
4104         key = key;
4105
4106         // Send our endlevel packet at regular intervals
4107
4108 //      if (timer_get_approx_seconds() > t1+ENDLEVEL_SEND_INTERVAL)
4109 //      {
4110 //              network_send_endlevel_packet();
4111 //              t1 = timer_get_approx_seconds();
4112 //      }
4113
4114         network_listen();
4115
4116         for (i = 0; i < N_players; i++)
4117         {
4118                 if ((Players[i].connected == 1) || (Players[i].connected == 0))
4119                         num_ready++;
4120         }
4121
4122         if (num_ready == N_players) // All players have checked in or are disconnected
4123         {
4124                 *key = -2;
4125         }
4126 }
4127
4128 void
4129 network_wait_for_requests(void)
4130 {
4131         // Wait for other players to load the level before we send the sync
4132         int choice, i;
4133         newmenu_item m[1];
4134         
4135         Network_status = NETSTAT_WAITING;
4136
4137         m[0].type=NM_TYPE_TEXT; m[0].text = TXT_NET_LEAVE;
4138
4139         mprintf((0, "Entered wait_for_requests : N_players = %d.\n", N_players));
4140
4141         for (choice = 0; choice < N_players; choice++)
4142                 mprintf((0, "Players[%d].connected = %d.\n", choice, Players[choice].connected));
4143
4144         Network_status = NETSTAT_WAITING;
4145         network_flush();
4146
4147         Players[Player_num].connected = 1;
4148
4149 menu:
4150         choice = newmenu_do(NULL, TXT_WAIT, 1, m, network_request_poll);        
4151
4152         if (choice == -1)
4153         {
4154                 // User aborted
4155                 choice = nm_messagebox(NULL, 3, TXT_YES, TXT_NO, TXT_START_NOWAIT, TXT_QUITTING_NOW);
4156                 if (choice == 2)
4157                         return;
4158                 if (choice != 0)
4159                         goto menu;
4160                 
4161                 // User confirmed abort
4162                 
4163                 for (i=0; i < N_players; i++) {
4164                         if ((Players[i].connected != 0) && (i != Player_num)) {
4165                                 if (Network_game_type == IPX_GAME)
4166                                         network_dump_player(NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node, DUMP_ABORTED);
4167                                 #ifdef MACINTOSH
4168                                 else
4169                                         network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node, NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, DUMP_ABORTED);
4170                                 #endif
4171                         }
4172                 }
4173
4174                 #ifdef MACINTOSH
4175                 if (Network_game_type == APPLETALK_GAME)
4176                         network_release_registered_game();
4177                 #endif
4178                 longjmp(LeaveGame, 0);  
4179         }
4180         else if (choice != -2)
4181                 goto menu;
4182 }
4183
4184 int
4185 network_level_sync(void)
4186 {
4187         // Do required syncing between (before) levels
4188
4189         int result;
4190
4191         mprintf((0, "Player %d entering network_level_sync.\n", Player_num));
4192         
4193         MySyncPackInitialized = 0;
4194
4195 //      my_segments_checksum = netmisc_calc_checksum(Segments, sizeof(segment)*(Highest_segment_index+1));
4196
4197         network_flush(); // Flush any old packets
4198
4199         if (N_players == 0)
4200                 result = network_wait_for_sync();
4201         else if (network_i_am_master())
4202         {
4203                 network_wait_for_requests();
4204                 network_send_sync();
4205                 result = 0;
4206         }
4207         else
4208                 result = network_wait_for_sync();
4209
4210    network_count_powerups_in_mine();
4211
4212         if (result)
4213         {
4214                 Players[Player_num].connected = 0;
4215                 network_send_endlevel_packet();
4216                 #ifdef MACINTOSH
4217                 if (Network_game_type == APPLETALK_GAME)
4218                         network_release_registered_game();
4219                 #endif
4220                 longjmp(LeaveGame, 0);
4221         }
4222         return(0);
4223 }
4224
4225 void network_count_powerups_in_mine(void)
4226  {
4227   int i;
4228
4229   for (i=0;i<MAX_POWERUP_TYPES;i++)
4230         PowerupsInMine[i]=0;
4231         
4232   for (i=0;i<=Highest_object_index;i++) 
4233         {
4234          if (Objects[i].type==OBJ_POWERUP)
4235           {
4236                 PowerupsInMine[Objects[i].id]++;
4237                 if (multi_powerup_is_4pack(Objects[i].id))
4238                    PowerupsInMine[Objects[i].id-1]+=4;
4239           }
4240         }
4241                   
4242  }
4243
4244 #ifdef MACINTOSH
4245
4246 // code to release the NBP binding of an appletalk game
4247
4248 void network_release_registered_game()
4249 {
4250         if (Network_game_type == APPLETALK_GAME)
4251                 appletalk_remove_netgame();
4252 }
4253
4254 // code to sort zone lists....
4255
4256 int zone_sort_func(const char **e0, const char **e1)
4257 {
4258         return strcmp(*e0, *e1);
4259 }
4260
4261 void network_get_appletalk_zone()
4262 {
4263         int num_zones, i, item, default_item;
4264         char **zone_list;
4265         char default_zone[MAX_ZONE_LENGTH];                     // my zone
4266
4267         Network_zone_name[0] = '\0';
4268         
4269         show_boxed_message("Looking for AppleTalk Zones");
4270         num_zones = appletalk_get_zone_names(&zone_list);
4271         clear_boxed_message();
4272
4273         if (num_zones < 0)      {               // error in getting zone list...maybe no router available....
4274                 if ( (num_zones == tooManyReqs) || (num_zones == noDataArea) ){
4275                         nm_messagebox(NULL, 1, TXT_OK, "AppleTalk Network is too busy.\nPlease try again shortly.");
4276                         longjmp(LeaveGame,0);
4277                 }
4278                 num_zones = 0;
4279         }
4280         
4281         if (num_zones == 0) {
4282                 strcpy(Network_zone_name, DEFAULT_ZONE_NAME);
4283                 return;
4284         }
4285         
4286         if (num_zones == 1) {
4287                 Network_zone_name[0] = (char)(strlen(zone_list[0]));
4288                 memcpy( &(Network_zone_name[1]), zone_list[0], strlen(zone_list[0]) );
4289                 goto zone_done;
4290         }
4291         
4292 // sort the zone names
4293
4294         for (i = 0; i < num_zones; i++)
4295                 strlwr(zone_list[i]);
4296
4297         qsort(zone_list, num_zones, sizeof(char *), zone_sort_func);
4298
4299 // get my current zone so we can highlight that one first
4300
4301         if (appletalk_get_my_zone(default_zone))
4302                 default_item = 0;
4303         else {
4304                 for (i = 0; i < num_zones; i++) {
4305                         if ( !stricmp(zone_list[i], default_zone) ) {
4306                                 default_item = i;
4307                                 break;
4308                         }
4309                 }
4310         }
4311
4312 rezone:         
4313         item = newmenu_listbox1("AppleTalk Zones", num_zones, zone_list, 0, default_item, NULL);
4314         
4315         if (item == -1)
4316                 goto rezone;
4317                 
4318         Network_zone_name[0] = (char)(strlen(zone_list[item]));
4319         memcpy( &(Network_zone_name[1]), zone_list[item], strlen(zone_list[item]) );
4320         
4321 zone_done:
4322         for (i = 0; i < num_zones; i++)
4323                 d_free(zone_list[i]);
4324         d_free(zone_list);
4325 }
4326 #endif
4327
4328 void nm_draw_background1(char * filename);
4329
4330 void network_join_game()
4331 {
4332         int choice, i;
4333         char menu_text[MAX_ACTIVE_NETGAMES+2][200];
4334         
4335         newmenu_item m[MAX_ACTIVE_NETGAMES+2];
4336
4337         if (Network_game_type == IPX_GAME) {
4338                 if ( !Network_active )
4339                 {
4340                         nm_messagebox(NULL, 1, TXT_OK, TXT_IPX_NOT_FOUND);
4341                         return;
4342                 }
4343         #ifdef MACINTOSH
4344         } else if (Appletalk_active <= 0) {
4345                 char buf[256];
4346                 
4347                 switch (Appletalk_active) {
4348                         case APPLETALK_NOT_OPEN:
4349                                 sprintf(buf, "Appletalk is not currently active.\nPlease enable AppleTalk from the\nChooser and restart Descent.");
4350                                 break;
4351                         case APPLETALK_BAD_LISTENER:
4352                                 sprintf(buf, "The Resource Fork of Descent appears damaged.\nPlease re-install Descent or contact\nMacPlay technical support.");
4353                                 break;
4354                         case APPLETALK_NO_LOCAL_ADDR:
4355                                 sprintf(buf, "Wow! Strange!\n\nNo Local Address.");
4356                                 break;
4357                         case APPLETALK_NO_SOCKET:
4358                                 sprintf(buf, "All AppleTalk sockets are in use.\nTry shutting down other network\napplications and restarting Descent.\n");
4359                                 break;
4360                 }
4361                 nm_messagebox(NULL, 1, TXT_OK, buf);
4362                 return;
4363         #endif
4364         }
4365
4366         network_init();
4367
4368         N_players = 0;
4369
4370         setjmp(LeaveGame);
4371         
4372         #ifdef MACINTOSH
4373         if (Network_game_type == APPLETALK_GAME)
4374                 network_get_appletalk_zone();
4375         #endif
4376         
4377         Network_send_objects = 0; 
4378         Network_sending_extras=0;
4379         Network_rejoined=0;
4380           
4381         Network_status = NETSTAT_BROWSING; // We are looking at a game menu
4382         
4383    network_flush();
4384         network_listen();  // Throw out old info
4385
4386         #ifdef MACINTOSH
4387         if (Network_game_type == IPX_GAME)
4388         #endif          // note link to if
4389                 network_send_game_list_request(); // broadcast a request for lists
4390
4391         num_active_games = 0;
4392
4393    memset(m, 0, sizeof(newmenu_item)*MAX_ACTIVE_NETGAMES);
4394    memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
4395    memset(ActiveNetPlayers,0,sizeof(AllNetPlayers_info)*MAX_ACTIVE_NETGAMES);
4396         
4397         gr_set_fontcolor(BM_XRGB(15,15,23),-1);
4398
4399         m[0].text = menu_text[0];
4400         m[0].type = NM_TYPE_TEXT;
4401         if (Network_game_type == IPX_GAME) {
4402                 if (Network_allow_socket_changes)
4403                         sprintf( m[0].text, "\tCurrent IPX Socket is default %+d (PgUp/PgDn to change)", Network_socket );
4404                 else
4405                         sprintf( m[0].text, "" );
4406         #ifdef MACINTOSH
4407         } else {
4408                 p2cstr(Network_zone_name);
4409                 if (strcmp(Network_zone_name, "*"))             // only print if there is a zone name
4410                         sprintf(m[0].text, "\tCurrent Zone is %s", Network_zone_name);          // is Network_zone_name a pascal string????
4411                 c2pstr(Network_zone_name);
4412         #endif
4413         }
4414
4415         m[1].text=menu_text[1];
4416         m[1].type=NM_TYPE_TEXT;
4417         sprintf (m[1].text,"\tGAME \tMODE \t#PLYRS \tMISSION \tLEV \tSTATUS");
4418
4419         for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
4420                 m[i+2].text = menu_text[i+2];
4421                 m[i+2].type = NM_TYPE_MENU;
4422                 sprintf(m[i+2].text, "%d.                                                               ", i+1);
4423                 m[i+2].redraw = 1;
4424         }
4425
4426         Network_games_changed = 1;      
4427 remenu:
4428         SurfingNet=1;
4429         nm_draw_background1(Menu_pcx_name);             //load this here so if we abort after loading level, we restore the palette
4430         gr_palette_load(gr_palette);
4431    ExtGameStatus=GAMESTAT_JOIN_NETGAME;
4432         choice=newmenu_dotiny("NETGAMES", NULL,MAX_ACTIVE_NETGAMES+2, m, network_join_poll);
4433         SurfingNet=0;
4434
4435         if (choice==-1) {
4436                 Network_status = NETSTAT_MENU;
4437                 return; // they cancelled               
4438         }               
4439    choice-=2;
4440
4441         if (choice >=num_active_games)
4442         {
4443                 nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_INVALID_CHOICE);
4444                 goto remenu;
4445         }
4446
4447         // Choice has been made and looks legit
4448         if (Active_games[choice].game_status == NETSTAT_ENDLEVEL)
4449         {
4450                 nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_NET_GAME_BETWEEN2);
4451                 goto remenu;
4452         }
4453
4454         if (Active_games[choice].protocol_version != MULTI_PROTO_VERSION)
4455         {
4456                 if (Active_games[choice].protocol_version == 3) {
4457                         #ifndef SHAREWARE
4458                                 nm_messagebox(TXT_SORRY, 1, TXT_OK, "Your version of Descent 2\nis incompatible with the\nDemo version");
4459                         #endif
4460                 }
4461                 else if (Active_games[choice].protocol_version == 4) {
4462                         #ifdef SHAREWARE
4463                                 nm_messagebox(TXT_SORRY, 1, TXT_OK, "This Demo version of\nDescent 2 is incompatible\nwith the full commercial version");
4464                         #endif
4465                 }
4466                 else
4467                         nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_VERSION_MISMATCH);
4468
4469                 goto remenu;
4470         }
4471
4472 #ifndef SHAREWARE
4473         {       
4474                 // Check for valid mission name
4475                         mprintf((0, "Loading mission:%s.\n", Active_games[choice].mission_name));
4476                         if (!load_mission_by_name(Active_games[choice].mission_name))
4477                         {
4478                                 nm_messagebox(NULL, 1, TXT_OK, TXT_MISSION_NOT_FOUND);
4479                                 goto remenu;
4480                         }
4481         }
4482 #endif
4483
4484 #if defined (D2_OEM)
4485         {
4486                 if (Active_games[choice].levelnum>8)
4487                  {
4488                                 nm_messagebox(NULL, 1, TXT_OK, "This OEM version only supports\nthe first 8 levels!");
4489                                 goto remenu;
4490                  }
4491         }
4492 #endif                  
4493
4494      if (!network_wait_for_all_info (choice))
4495                 {
4496                   nm_messagebox (TXT_SORRY,1,TXT_OK,"There was a join error!");
4497                   Network_status = NETSTAT_BROWSING; // We are looking at a game menu
4498                   goto remenu;
4499                 }       
4500           
4501           Network_status = NETSTAT_BROWSING; // We are looking at a game menu
4502  
4503      if (!can_join_netgame(&Active_games[choice],&ActiveNetPlayers[choice]))
4504                         {
4505                                 if (Active_games[choice].numplayers == Active_games[choice].max_numplayers)
4506                                         nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_GAME_FULL);
4507                                 else
4508                                         nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_IN_PROGRESS);
4509                                 goto remenu;
4510                         }
4511
4512         // Choice is valid, prepare to join in
4513
4514         memcpy(&Netgame, &Active_games[choice], sizeof(netgame_info));
4515    memcpy (&NetPlayers,&ActiveNetPlayers[choice],sizeof(AllNetPlayers_info));
4516
4517         Difficulty_level = Netgame.difficulty;
4518         MaxNumNetPlayers = Netgame.max_numplayers;
4519         change_playernum_to(1);
4520
4521         #ifdef MACINTOSH
4522
4523 // register the joining player with NBP.  This will have the nice effect of a player wanting to
4524 // join to be able to see the netgame if this player were to become the master.
4525
4526         if (Network_game_type == APPLETALK_GAME) {
4527                 OSErr err;
4528                 int count = 0;
4529                 fix t1;
4530                 
4531                 show_boxed_message("Registering Netgame");
4532                 do {
4533                         err = appletalk_register_netgame( Active_games[choice].game_name, TickCount() );
4534                         t1 = timer_get_fixed_seconds() + F1_0;
4535                         while ( timer_get_fixed_seconds() < t1 ) ;
4536                         count++;
4537                 } while ( (err == nbpDuplicate) && (count != MAX_REGISTER_TRIES) );
4538                 clear_boxed_message();
4539                 if ( (err == tooManyReqs) || (count == MAX_REGISTER_TRIES) ) {
4540                         nm_messagebox(NULL, 1, TXT_OK, "AppleTalk Network is too busy.\nPlease try again shortly.");
4541                         goto remenu;
4542                 }
4543         }
4544         #endif
4545
4546         network_set_game_mode(Netgame.gamemode);
4547
4548         network_AdjustMaxDataSize ();
4549
4550         StartNewLevel(Netgame.levelnum, 0);
4551
4552         return;         // look ma, we're in a game!!!
4553 }
4554
4555 void network_AdjustMaxDataSize ()
4556  {
4557           
4558    if (Netgame.ShortPackets)
4559         MaxXDataSize=NET_XDATA_SIZE;
4560    else
4561       MaxXDataSize=NET_XDATA_SIZE;
4562  }
4563   
4564
4565 fix StartWaitAllTime=0;
4566 int WaitAllChoice=0;
4567 #define ALL_INFO_REQUEST_INTERVAL F1_0*3
4568
4569 void network_wait_all_poll( int nitems, newmenu_item * menus, int * key, int citem )
4570  {
4571   static fix t1=0;
4572
4573   menus=menus;
4574   nitems=nitems;
4575   citem=citem;
4576
4577   if (timer_get_approx_seconds() > t1+ALL_INFO_REQUEST_INTERVAL)
4578         {
4579                 network_send_all_info_request(PID_SEND_ALL_GAMEINFO,SecurityCheck);
4580                 t1 = timer_get_approx_seconds();
4581         }
4582
4583   network_do_big_wait(WaitAllChoice);  
4584    
4585   if(SecurityCheck==-1)
4586    *key=-2;
4587  }
4588  
4589 int network_wait_for_all_info (int choice)
4590  {
4591   int pick;
4592   
4593   newmenu_item m[2];
4594
4595   m[0].type=NM_TYPE_TEXT; m[0].text = "Press Escape to cancel";
4596
4597   WaitAllChoice=choice;
4598   StartWaitAllTime=timer_get_approx_seconds();
4599   SecurityCheck=Active_games[choice].Security;
4600   NetSecurityFlag=0;
4601
4602   GetMenu:
4603   pick=newmenu_do( NULL, "Connecting...", 1, m, network_wait_all_poll );
4604
4605   if (pick>-1 && SecurityCheck!=-1)
4606         goto GetMenu;
4607
4608   if (SecurityCheck==-1)
4609     {   
4610            SecurityCheck=0;     
4611            return (1);
4612          }
4613   SecurityCheck=0;      
4614   return (0);
4615  }
4616
4617 void network_do_big_wait(int choice)
4618 {
4619         int size;
4620         ubyte packet[IPX_MAX_DATA_SIZE],*data;
4621         AllNetPlayers_info *temp_info;
4622 #ifdef MACINTOSH
4623         AllNetPlayers_info info_struct;
4624         ubyte apacket[APPLETALK_MAX_DATA_SIZE];
4625 #endif
4626   
4627         #ifdef MACINTOSH
4628         if (Network_game_type == APPLETALK_GAME)
4629                 size=appletalk_get_packet_data( apacket );
4630         else
4631         #endif
4632                 size=ipx_get_packet_data( packet );
4633         
4634   if (size>0)
4635         {
4636                 #ifdef MACINTOSH
4637                 if (Network_game_type == APPLETALK_GAME)
4638                         data = apacket;
4639                 else
4640                 #endif
4641                         data = packet;
4642   
4643          switch (data[0])
4644      {  
4645                 case PID_GAME_INFO:
4646
4647                 if (Network_game_type == IPX_GAME) {
4648                         #ifndef MACINTOSH
4649                         memcpy((ubyte *)&TempNetInfo, data, sizeof(netgame_info));
4650                         #else
4651                         receive_netgame_packet(data, &TempNetInfo, 0);
4652                         #endif
4653                 } else {
4654                         memcpy((ubyte *)&TempNetInfo, data, sizeof(netgame_info));
4655                 }
4656                 mprintf ((0,"This is %s game with a security of %d\n",TempNetInfo.game_name,TempNetInfo.Security));
4657
4658       if (TempNetInfo.Security !=SecurityCheck)
4659                  {
4660                   mprintf ((0,"Bad security on big_wait...rejecting.\n"));      
4661                   break;
4662                  }
4663                       
4664       if (NetSecurityFlag==NETSECURITY_WAIT_FOR_GAMEINFO)
4665            {
4666                    if (TempPlayersInfo->Security==TempNetInfo.Security)
4667                         {
4668                           mprintf ((0,"EQUAL !: Game=%d Players=%d ",TempPlayersInfo->Security,TempNetInfo.Security));
4669                 if (TempPlayersInfo->Security==SecurityCheck)
4670                           {
4671                                         memcpy (&Active_games[choice],(ubyte *)&TempNetInfo,sizeof(netgame_info));
4672                                         memcpy (&ActiveNetPlayers[choice],TempPlayersInfo,sizeof(AllNetPlayers_info));
4673                                         SecurityCheck=-1;
4674                           }
4675                         }
4676            }
4677                 else
4678            {
4679               NetSecurityFlag=NETSECURITY_WAIT_FOR_PLAYERS;
4680               NetSecurityNum=TempNetInfo.Security;
4681                                     
4682               if (network_wait_for_playerinfo())
4683                         {
4684                            mprintf ((0,"HUH? Game=%d Player=%d\n",NetSecurityNum,TempPlayersInfo->Security));
4685                                 memcpy (&Active_games[choice],(ubyte *)&TempNetInfo,sizeof(netgame_info));
4686                                 memcpy (&ActiveNetPlayers[choice],TempPlayersInfo,sizeof(AllNetPlayers_info));
4687                                 SecurityCheck=-1;
4688                         }
4689               NetSecurityFlag=0;
4690               NetSecurityNum=0;
4691            }
4692         break;
4693       case PID_PLAYERSINFO:
4694                mprintf ((0,"Got a PID_PLAYERSINFO!\n"));
4695
4696                         if (Network_game_type == IPX_GAME) {
4697                                 #ifndef MACINTOSH
4698                                 temp_info=(AllNetPlayers_info *)data;
4699                                 #else
4700                                 receive_netplayers_packet(data, &info_struct);
4701                                 temp_info = &info_struct;
4702                                 #endif
4703                         } else {
4704                                 temp_info = (AllNetPlayers_info *)data;
4705                         }
4706                         if (temp_info->Security!=SecurityCheck) 
4707                                 break;     // If this isn't the guy we're looking for, move on
4708
4709                         memcpy (&TempPlayersBase,(ubyte *)&temp_info,sizeof(AllNetPlayers_info));
4710                         TempPlayersInfo=&TempPlayersBase;
4711                         WaitingForPlayerInfo=0;
4712                         NetSecurityNum=TempPlayersInfo->Security;
4713                         NetSecurityFlag=NETSECURITY_WAIT_FOR_GAMEINFO;
4714                         break;
4715            }
4716         }
4717 }
4718
4719 void network_leave_game()
4720
4721    int nsave;
4722                 
4723         network_do_frame(1, 1);
4724    
4725    #ifdef NETPROFILING
4726         fclose (SendLogFile);
4727            fclose (RecieveLogFile);
4728         #endif
4729
4730         if ((network_i_am_master()))
4731         {
4732                 while (Network_sending_extras>1 && Player_joining_extras!=-1)
4733                   network_send_extras();
4734    
4735                 Netgame.numplayers = 0;
4736            nsave=N_players;
4737            N_players=0;
4738                 network_send_game_info(NULL);
4739                 N_players=nsave;
4740                 
4741                 mprintf ((0,"HEY! I'm master and I've left.\n"));
4742         }
4743         
4744         Players[Player_num].connected = 0;
4745         network_send_endlevel_packet();
4746         change_playernum_to(0);
4747         Game_mode = GM_GAME_OVER;
4748    write_player_file();
4749
4750 //      WIN(ipx_destroy_read_thread());
4751
4752         network_flush();
4753 }
4754
4755 void network_flush()
4756 {
4757         #ifdef MACINTOSH
4758         ubyte apacket[APPLETALK_MAX_DATA_SIZE];
4759         #endif
4760         ubyte packet[IPX_MAX_DATA_SIZE];
4761
4762         #ifdef MACINTOSH
4763         if ( (Network_game_type == APPLETALK_GAME) && (Appletalk_active <= 0) )
4764                 return;
4765         #endif
4766         
4767         if ( Network_game_type == IPX_GAME )
4768                 if (!Network_active) return;
4769
4770         #ifdef MACINTOSH
4771         if (Network_game_type == APPLETALK_GAME)
4772                 while (appletalk_get_packet_data(apacket) > 0) ;
4773         else
4774         #endif
4775                 while (ipx_get_packet_data(packet) > 0) ;
4776 }
4777
4778 void network_listen()
4779 {
4780         #ifdef MACINTOSH
4781         ubyte apacket[APPLETALK_MAX_DATA_SIZE];
4782         #endif
4783         int size;
4784         ubyte packet[IPX_MAX_DATA_SIZE];
4785         int i,loopmax=999;
4786
4787         if (Network_status==NETSTAT_PLAYING && Netgame.ShortPackets && !Network_send_objects)
4788          {
4789                 loopmax=N_players*Netgame.PacketsPerSec;
4790          }
4791         
4792         #ifdef MACINTOSH
4793         if ( (Network_game_type == APPLETALK_GAME) && (Appletalk_active <= 0) )
4794                 return;
4795         #endif
4796
4797         if (Network_game_type == IPX_GAME)      
4798                 if (!Network_active) return;
4799
4800         if (!(Game_mode & GM_NETWORK) && (Function_mode == FMODE_GAME))
4801                 mprintf((0, "Calling network_listen() when not in net game.\n"));
4802
4803         WaitingForPlayerInfo=1;
4804         NetSecurityFlag=NETSECURITY_OFF;
4805
4806         i=1;
4807         if (Network_game_type == IPX_GAME) {
4808                 size = ipx_get_packet_data( packet );
4809                 while ( size > 0)       {
4810                         network_process_packet( packet, size );
4811                         if (++i>loopmax)
4812                          break;
4813                         size = ipx_get_packet_data( packet );
4814                 }
4815         #ifdef MACINTOSH
4816         } else {
4817                 size = appletalk_get_packet_data( apacket );
4818                 while ( size > 0)       {
4819                         network_process_packet( apacket, size );
4820                         if (++i>loopmax)
4821                          break;
4822                         size = appletalk_get_packet_data( apacket );
4823                 }
4824         #endif
4825         }
4826 }
4827
4828 int network_wait_for_playerinfo()
4829 {
4830         int size,retries=0;
4831         ubyte packet[IPX_MAX_DATA_SIZE];
4832         struct AllNetPlayers_info *TempInfo;
4833         fix basetime;
4834         ubyte id;
4835 #ifdef MACINTOSH
4836         AllNetPlayers_info info_struct;
4837         ubyte apacket[APPLETALK_MAX_DATA_SIZE];
4838 #endif
4839
4840         #ifdef MACINTOSH
4841         if ( (Network_game_type == APPLETALK_GAME) && (Appletalk_active <= 0) )
4842                 return;
4843         #endif
4844
4845         if ( Network_game_type == IPX_GAME)
4846                 if (!Network_active) return(0);
4847                 
4848       //  if (!WaitingForPlayerInfo)
4849         // return (1);
4850
4851         if (!(Game_mode & GM_NETWORK) && (Function_mode == FMODE_GAME))
4852                 {
4853         mprintf((0, "Calling network_wait_for_playerinfo() when not in net game.\n"));
4854                 }       
4855         if (Network_status==NETSTAT_PLAYING)
4856          {
4857                   Int3(); //MY GOD! Get Jason...this is the source of many problems
4858              return (0);
4859          }
4860    basetime=timer_get_approx_seconds();
4861
4862    while (WaitingForPlayerInfo && retries<50 && (timer_get_approx_seconds()<(basetime+(F1_0*5))))
4863       {
4864                 if (Network_game_type == IPX_GAME) {
4865                         size = ipx_get_packet_data( packet );
4866                         id = packet[0];
4867                 } else {
4868                         #ifdef MACINTOSH
4869                         size = appletalk_get_packet_data( apacket );
4870                         id = apacket[0];
4871                         #endif
4872                 }
4873
4874         if (size>0 && id==PID_PLAYERSINFO)
4875         {
4876                 #ifdef MACINTOSH
4877                 if (Network_game_type == APPLETALK_GAME) {
4878                         TempInfo = (AllNetPlayers_info *)apacket;
4879                 } else {
4880                         receive_netplayers_packet(packet, &info_struct);
4881                         TempInfo = &info_struct;
4882                 }
4883                 #else
4884                 TempInfo=(AllNetPlayers_info *)packet;
4885                 #endif
4886     
4887                 retries++;
4888
4889             if (NetSecurityFlag==NETSECURITY_WAIT_FOR_PLAYERS)
4890              {
4891               if (NetSecurityNum==TempInfo->Security)
4892                {
4893                 mprintf ((0,"HEYEQUAL: Player=%d Game=%d\n",TempInfo->Security,NetSecurityNum));
4894                 memcpy (&TempPlayersBase,(ubyte *)TempInfo,sizeof(AllNetPlayers_info));
4895                 TempPlayersInfo=&TempPlayersBase;
4896                 NetSecurityFlag=NETSECURITY_OFF;
4897                 NetSecurityNum=0;
4898                 WaitingForPlayerInfo=0;
4899                 return (1);
4900                }
4901               else
4902                continue;
4903              }
4904             else
4905              {
4906               mprintf ((0,"I'm original!\n"));
4907
4908               NetSecurityNum=TempInfo->Security;
4909               NetSecurityFlag=NETSECURITY_WAIT_FOR_GAMEINFO;
4910            
4911               memcpy (&TempPlayersBase,(ubyte *)TempInfo,sizeof(AllNetPlayers_info));
4912               TempPlayersInfo=&TempPlayersBase;
4913               WaitingForPlayerInfo=0;
4914               return (1);
4915              }
4916            }
4917          }
4918    return (0);
4919   }
4920
4921
4922 void network_send_data( ubyte * ptr, int len, int urgent )
4923 {
4924         char check;
4925
4926    #ifdef NETPROFILING
4927            TTSent[ptr[0]]++;  
4928            fprintf (SendLogFile,"Packet type: %d Len:%d Urgent:%d TT=%d\n",ptr[0],len,urgent,TTSent[ptr[0]]);
4929            fflush (SendLogFile);
4930         #endif
4931     
4932         if (Endlevel_sequence)
4933                 return;
4934
4935         if (!MySyncPackInitialized)     {
4936                 MySyncPackInitialized = 1;
4937                 memset( &MySyncPack, 0, sizeof(frame_info) );
4938         }
4939         
4940         if (urgent)
4941                 PacketUrgent = 1;
4942
4943         if ((MySyncPack.data_size+len) > MaxXDataSize ) {
4944                 check = ptr[0];
4945                 network_do_frame(1, 0);
4946                 if (MySyncPack.data_size != 0) {
4947                         mprintf((0, "%d bytes were added to data by network_do_frame!\n", MySyncPack.data_size));
4948                         Int3();
4949                 }
4950 //              Int3();         // Trying to send too much!
4951 //              return;
4952                 mprintf((0, "Packet overflow, sending additional packet, type %d len %d.\n", ptr[0], len));
4953                 Assert(check == ptr[0]);
4954         }
4955
4956         Assert(MySyncPack.data_size+len <= MaxXDataSize);
4957
4958         memcpy( &MySyncPack.data[MySyncPack.data_size], ptr, len );
4959         MySyncPack.data_size += len;
4960 }
4961
4962 void network_timeout_player(int playernum)
4963 {
4964         // Remove a player from the game if we haven't heard from them in 
4965         // a long time.
4966         int i, n = 0;
4967
4968         Assert(playernum < N_players);
4969         Assert(playernum > -1);
4970
4971         network_disconnect_player(playernum);
4972         create_player_appearance_effect(&Objects[Players[playernum].objnum]);
4973
4974         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
4975
4976         HUD_init_message("%s %s", Players[playernum].callsign, TXT_DISCONNECTING);
4977         for (i = 0; i < N_players; i++)
4978                 if (Players[i].connected) 
4979                         n++;
4980
4981         if (n == 1)
4982         {
4983                 nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
4984         }
4985 }
4986
4987 fix last_send_time = 0;
4988 fix last_timeout_check = 0;
4989
4990 #ifdef MACINTOSH
4991 void squish_short_frame_info(short_frame_info old_info, ubyte *data)
4992 {
4993         int loc = 0;
4994         int tmpi;
4995         short tmps;
4996         
4997         data[0] = old_info.type;                              loc++;  loc += 3;               // skip three for pad byte
4998         tmpi = swapint(old_info.numpackets);
4999         memcpy(&(data[loc]), &tmpi, 4);                                                 loc += 4;
5000
5001         memcpy(&(data[loc]), old_info.thepos.bytemat, 9);               loc += 9;
5002         tmps = INTEL_SHORT(old_info.thepos.xo);
5003         memcpy(&(data[loc]), &tmps, 2);                 loc += 2;
5004         tmps = INTEL_SHORT(old_info.thepos.yo);
5005         memcpy(&(data[loc]), &tmps, 2);                 loc += 2;
5006         tmps = INTEL_SHORT(old_info.thepos.zo);
5007         memcpy(&(data[loc]), &tmps, 2);                 loc += 2;
5008         tmps = INTEL_SHORT(old_info.thepos.segment);
5009         memcpy(&(data[loc]), &tmps, 2);    loc += 2;
5010         tmps = INTEL_SHORT(old_info.thepos.velx);
5011         memcpy(&(data[loc]), &tmps, 2);               loc += 2;
5012         tmps = INTEL_SHORT(old_info.thepos.vely);
5013         memcpy(&(data[loc]), &tmps, 2);               loc += 2;
5014         tmps = INTEL_SHORT(old_info.thepos.velz);
5015         memcpy(&(data[loc]), &tmps, 2);               loc += 2;
5016
5017         tmps = swapshort(old_info.data_size);
5018         memcpy(&(data[loc]), &tmps, 2);                                                 loc += 2;
5019
5020         data[loc] = old_info.playernum; loc++;
5021         data[loc] = old_info.obj_render_type; loc++;
5022         data[loc] = old_info.level_num; loc++;
5023         memcpy(&(data[loc]), old_info.data, old_info.data_size);
5024 }
5025 #endif
5026
5027 char NakedBuf[NET_XDATA_SIZE+4];
5028 int NakedPacketLen=0;
5029 int NakedPacketDestPlayer=-1;
5030
5031 void network_do_frame(int force, int listen)
5032 {
5033         int i;
5034         short_frame_info ShortSyncPack;
5035         static fix LastEndlevel=0;
5036
5037         if (!(Game_mode&GM_NETWORK)) return;
5038
5039         if ((Network_status != NETSTAT_PLAYING) || (Endlevel_sequence)) // Don't send postion during escape sequence...
5040                 goto listen;
5041
5042   if (NakedPacketLen)
5043         {
5044                 Assert (NakedPacketDestPlayer>-1);
5045 //         mprintf ((0,"Sending a naked packet to %s (%d bytes)!\n",Players[NakedPacketDestPlayer].callsign,NakedPacketLen));
5046                 if (Network_game_type == IPX_GAME) 
5047                         ipx_send_packet_data( (ubyte *)NakedBuf, NakedPacketLen, NetPlayers.players[NakedPacketDestPlayer].network.ipx.server, NetPlayers.players[NakedPacketDestPlayer].network.ipx.node,Players[NakedPacketDestPlayer].net_address );
5048                 #ifdef MACINTOSH
5049                 else
5050                         appletalk_send_packet_data( (ubyte *)NakedBuf, NakedPacketLen, NetPlayers.players[NakedPacketDestPlayer].network.appletalk.node, NetPlayers.players[NakedPacketDestPlayer].network.appletalk.net,NetPlayers.players[NakedPacketDestPlayer].network.appletalk.socket );
5051                 #endif
5052                 NakedPacketLen=0;
5053                 NakedPacketDestPlayer=-1;
5054    }
5055   
5056    if (WaitForRefuseAnswer && timer_get_approx_seconds()>(RefuseTimeLimit+(F1_0*12)))
5057                 WaitForRefuseAnswer=0;
5058                         
5059         last_send_time += FrameTime;
5060         last_timeout_check += FrameTime;
5061
5062    // Send out packet PacksPerSec times per second maximum... unless they fire, then send more often...
5063    if ( (last_send_time>F1_0/Netgame.PacketsPerSec) || (Network_laser_fired) || force || PacketUrgent )       {        
5064                 if ( Players[Player_num].connected )    {
5065                         int objnum = Players[Player_num].objnum;
5066                         PacketUrgent = 0;
5067
5068                         if (listen) {
5069                                 multi_send_robot_frame(0);
5070                                 multi_send_fire();              // Do firing if needed..
5071                         }
5072
5073                         last_send_time = 0;
5074
5075                         if (Netgame.ShortPackets)
5076                         {
5077 #ifdef MACINTOSH
5078                                 ubyte send_data[IPX_MAX_DATA_SIZE];
5079                                 int squished_size;
5080 #endif
5081                                 create_shortpos(&ShortSyncPack.thepos, Objects+objnum, 0);
5082                                 ShortSyncPack.type                                      = PID_PDATA;
5083                                 ShortSyncPack.playernum                         = Player_num;
5084                                 ShortSyncPack.obj_render_type           = Objects[objnum].render_type;
5085                                 ShortSyncPack.level_num                         = Current_level_num;
5086                                 ShortSyncPack.data_size                         = MySyncPack.data_size;
5087                                 memcpy (&ShortSyncPack.data[0],&MySyncPack.data[0],MySyncPack.data_size);
5088
5089                                 for (i=0; i<N_players; i++ )    {
5090                                         if ( (Players[i].connected) && (i!=Player_num ) )       {
5091                                                 MySyncPack.numpackets = Players[i].n_packets_sent++;
5092                                                 ShortSyncPack.numpackets=MySyncPack.numpackets;
5093                                                 if (Network_game_type == IPX_GAME) {
5094                                                         #ifndef MACINTOSH
5095                                                         ipx_send_packet_data( (ubyte *)&ShortSyncPack, sizeof(short_frame_info)-MaxXDataSize+MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address );
5096                                                         #else
5097                                                         squish_short_frame_info(ShortSyncPack, send_data);
5098                                                         ipx_send_packet_data( (ubyte *)send_data, IPX_SHORT_INFO_SIZE-MaxXDataSize+MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address );
5099                                                         #endif
5100                                                 #ifdef MACINTOSH
5101                                                 } else {
5102                                                         appletalk_send_packet_data( (ubyte *)&ShortSyncPack, sizeof(short_frame_info)-MaxXDataSize+MySyncPack.data_size, NetPlayers.players[i].network.appletalk.node, NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket );
5103                                                 #endif
5104                                                 }
5105                                         }
5106                                 }
5107                         }
5108                         else  // If long packets
5109                         {
5110                                 int send_data_size;
5111                                 
5112                                 MySyncPack.type                                 = PID_PDATA;
5113                                 MySyncPack.playernum                    = Player_num;
5114                                 MySyncPack.obj_render_type              = Objects[objnum].render_type;
5115                                 MySyncPack.level_num                    = Current_level_num;
5116                                 MySyncPack.obj_segnum                   = Objects[objnum].segnum;
5117                                 MySyncPack.obj_pos                              = Objects[objnum].pos;
5118                                 MySyncPack.obj_orient                   = Objects[objnum].orient;
5119                                 MySyncPack.phys_velocity                = Objects[objnum].mtype.phys_info.velocity;
5120                                 MySyncPack.phys_rotvel                  = Objects[objnum].mtype.phys_info.rotvel;
5121                                 
5122                                 send_data_size = MySyncPack.data_size;                  // do this so correct size data is sent
5123
5124                                 #ifdef MACINTOSH                        // do the swap stuff
5125                                 if (Network_game_type == IPX_GAME) {
5126                                         MySyncPack.obj_segnum = INTEL_SHORT(MySyncPack.obj_segnum);
5127                                         MySyncPack.obj_pos.x = INTEL_INT((int)MySyncPack.obj_pos.x);
5128                                         MySyncPack.obj_pos.y = INTEL_INT((int)MySyncPack.obj_pos.y);
5129                                         MySyncPack.obj_pos.z = INTEL_INT((int)MySyncPack.obj_pos.z);
5130                                         
5131                                         MySyncPack.obj_orient.rvec.x = INTEL_INT((int)MySyncPack.obj_orient.rvec.x);
5132                                         MySyncPack.obj_orient.rvec.y = INTEL_INT((int)MySyncPack.obj_orient.rvec.y);
5133                                         MySyncPack.obj_orient.rvec.z = INTEL_INT((int)MySyncPack.obj_orient.rvec.z);
5134                                         MySyncPack.obj_orient.uvec.x = INTEL_INT((int)MySyncPack.obj_orient.uvec.x);
5135                                         MySyncPack.obj_orient.uvec.y = INTEL_INT((int)MySyncPack.obj_orient.uvec.y);
5136                                         MySyncPack.obj_orient.uvec.z = INTEL_INT((int)MySyncPack.obj_orient.uvec.z);
5137                                         MySyncPack.obj_orient.fvec.x = INTEL_INT((int)MySyncPack.obj_orient.fvec.x);
5138                                         MySyncPack.obj_orient.fvec.y = INTEL_INT((int)MySyncPack.obj_orient.fvec.y);
5139                                         MySyncPack.obj_orient.fvec.z = INTEL_INT((int)MySyncPack.obj_orient.fvec.z);
5140                                         
5141                                         MySyncPack.phys_velocity.x = INTEL_INT((int)MySyncPack.phys_velocity.x);
5142                                         MySyncPack.phys_velocity.y = INTEL_INT((int)MySyncPack.phys_velocity.y);
5143                                         MySyncPack.phys_velocity.z = INTEL_INT((int)MySyncPack.phys_velocity.z);
5144                                 
5145                                         MySyncPack.phys_rotvel.x = INTEL_INT((int)MySyncPack.phys_rotvel.x);
5146                                         MySyncPack.phys_rotvel.y = INTEL_INT((int)MySyncPack.phys_rotvel.y);
5147                                         MySyncPack.phys_rotvel.z = INTEL_INT((int)MySyncPack.phys_rotvel.z);
5148                                         
5149                                         MySyncPack.data_size = INTEL_SHORT(MySyncPack.data_size);
5150                                 }
5151                                 #endif
5152
5153                                 for (i=0; i<N_players; i++ )    {
5154                                         if ( (Players[i].connected) && (i!=Player_num ) )       {
5155                                                 if (Network_game_type == IPX_GAME)
5156                                                         MySyncPack.numpackets = INTEL_INT(Players[i].n_packets_sent);
5157                                                 #ifdef MACINTOSH
5158                                                 else
5159                                                         MySyncPack.numpackets = Players[i].n_packets_sent;
5160                                                 #endif
5161
5162                                                 Players[i].n_packets_sent++;
5163                                                 if (Network_game_type == IPX_GAME)
5164                                                         ipx_send_packet_data( (ubyte *)&MySyncPack, sizeof(frame_info)-MaxXDataSize+send_data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address );
5165                                                 #ifdef MACINTOSH
5166                                                 else
5167                                                         appletalk_send_packet_data( (ubyte *)&MySyncPack, sizeof(frame_info)-MaxXDataSize+send_data_size, NetPlayers.players[i].network.appletalk.node, NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket);
5168                                                 #endif
5169                                         }
5170                                 }
5171                         }
5172                                 
5173                         MySyncPack.data_size = 0;               // Start data over at 0 length.
5174                         if (Control_center_destroyed)
5175                         {
5176                                 if (Player_is_dead)
5177                                         Players[Player_num].connected=3;
5178                                 if (timer_get_approx_seconds() > (LastEndlevel+(F1_0/2)))
5179                                 {
5180                                         network_send_endlevel_packet();
5181                                         LastEndlevel=timer_get_approx_seconds();
5182                                 }
5183                         }
5184                         //mprintf( (0, "Packet has %d bytes appended (TS=%d)\n", MySyncPack.data_size, sizeof(frame_info)-MaxXDataSize+MySyncPack.data_size ));
5185                 }
5186         }
5187    
5188         if (!listen)
5189                 return;
5190
5191         if ((last_timeout_check > F1_0) && !(Control_center_destroyed))
5192         {
5193                 fix approx_time = timer_get_approx_seconds();
5194                 // Check for player timeouts
5195                 for (i = 0; i < N_players; i++)
5196                 {
5197                         if ((i != Player_num) && (Players[i].connected == 1))
5198                         {
5199                                 if ((LastPacketTime[i] == 0) || (LastPacketTime[i] > approx_time))
5200                                 {
5201                                         LastPacketTime[i] = approx_time;
5202                                         continue;
5203                                 }
5204                                 if ((approx_time - LastPacketTime[i]) > (15*F1_0))
5205                                         network_timeout_player(i);
5206                         }
5207                 }
5208                 last_timeout_check = 0;
5209         }
5210
5211 listen:
5212         if (!listen)
5213         {
5214                 MySyncPack.data_size = 0;
5215                 return;
5216         }
5217         network_listen();
5218
5219    if (VerifyPlayerJoined!=-1 && !(FrameCount & 63))
5220           resend_sync_due_to_packet_loss_for_allender(); // This will resend to network_player_rejoining
5221  
5222         if (Network_send_objects)
5223                 network_send_objects();
5224
5225         if (Network_sending_extras && VerifyPlayerJoined==-1)
5226         {
5227           network_send_extras();
5228           return;
5229     }
5230 }
5231
5232 int missed_packets = 0;
5233
5234 int ConsistencyCount = 0;
5235
5236 void network_consistency_error(void)
5237 {
5238         if (++ConsistencyCount < 10)
5239                 return;
5240
5241         Function_mode = FMODE_MENU;
5242         #ifndef MACINTOSH
5243         nm_messagebox(NULL, 1, TXT_OK, TXT_CONSISTENCY_ERROR);
5244         #else
5245         nm_messagebox(NULL, 1, TXT_OK, "Failed to join the netgame.\nYou are missing packets.  Check\nyour network connection and\ntry again.");
5246         #endif
5247         Function_mode = FMODE_GAME;
5248         ConsistencyCount = 0;
5249         multi_quit_game = 1;
5250         multi_leave_menu = 1;
5251         multi_reset_stuff();
5252         Function_mode = FMODE_MENU;
5253 }
5254
5255 void network_process_pdata (char *data)
5256  {
5257   Assert (Game_mode & GM_NETWORK);
5258  
5259   if (Netgame.ShortPackets)
5260         network_read_pdata_short_packet ((short_frame_info *)data);
5261   else
5262         network_read_pdata_packet ((frame_info *)data);
5263  }
5264
5265 void network_read_pdata_packet(frame_info *pd )
5266 {
5267         int TheirPlayernum;
5268         int TheirObjnum;
5269         object * TheirObj = NULL;
5270         
5271 // frame_info should be aligned...for mac, make the necessary adjustments
5272 #ifdef MACINTOSH
5273         if (Network_game_type == IPX_GAME) {
5274                 pd->numpackets = INTEL_INT(pd->numpackets);
5275                 pd->obj_pos.x = INTEL_INT(pd->obj_pos.x);
5276                 pd->obj_pos.y = INTEL_INT(pd->obj_pos.y);
5277                 pd->obj_pos.z = INTEL_INT(pd->obj_pos.z);
5278         
5279                 pd->obj_orient.rvec.x = (fix)INTEL_INT((int)pd->obj_orient.rvec.x);
5280                 pd->obj_orient.rvec.y = (fix)INTEL_INT((int)pd->obj_orient.rvec.y);
5281                 pd->obj_orient.rvec.z = (fix)INTEL_INT((int)pd->obj_orient.rvec.z);
5282                 pd->obj_orient.uvec.x = (fix)INTEL_INT((int)pd->obj_orient.uvec.x);
5283                 pd->obj_orient.uvec.y = (fix)INTEL_INT((int)pd->obj_orient.uvec.y);
5284                 pd->obj_orient.uvec.z = (fix)INTEL_INT((int)pd->obj_orient.uvec.z);
5285                 pd->obj_orient.fvec.x = (fix)INTEL_INT((int)pd->obj_orient.fvec.x);
5286                 pd->obj_orient.fvec.y = (fix)INTEL_INT((int)pd->obj_orient.fvec.y);
5287                 pd->obj_orient.fvec.z = (fix)INTEL_INT((int)pd->obj_orient.fvec.z);
5288         
5289                 pd->phys_velocity.x = (fix)INTEL_INT((int)pd->phys_velocity.x);
5290                 pd->phys_velocity.y = (fix)INTEL_INT((int)pd->phys_velocity.y);
5291                 pd->phys_velocity.z = (fix)INTEL_INT((int)pd->phys_velocity.z);
5292         
5293                 pd->phys_rotvel.x = (fix)INTEL_INT((int)pd->phys_rotvel.x);
5294                 pd->phys_rotvel.y = (fix)INTEL_INT((int)pd->phys_rotvel.y);
5295                 pd->phys_rotvel.z = (fix)INTEL_INT((int)pd->phys_rotvel.z);
5296                 
5297                 pd->obj_segnum = INTEL_SHORT(pd->obj_segnum);
5298                 pd->data_size = INTEL_SHORT(pd->data_size);
5299         }
5300 #endif
5301
5302         TheirPlayernum = pd->playernum;
5303         TheirObjnum = Players[pd->playernum].objnum;
5304         
5305         if (TheirPlayernum < 0) {
5306                 Int3(); // This packet is bogus!!
5307                 return;
5308         }
5309
5310    if (VerifyPlayerJoined!=-1 && TheirPlayernum==VerifyPlayerJoined)
5311          {
5312           // Hurray! Someone really really got in the game (I think).
5313      mprintf ((0,"Hurray! VPJ (%d) reset!\n",VerifyPlayerJoined));
5314      VerifyPlayerJoined=-1;
5315          }
5316  
5317         if (!multi_quit_game && (TheirPlayernum >= N_players)) {
5318                 if (Network_status!=NETSTAT_WAITING)
5319                  {
5320                         Int3(); // We missed an important packet!
5321                         network_consistency_error();
5322                         return;
5323                  }
5324                 else
5325                  return;
5326         }
5327         if (Endlevel_sequence || (Network_status == NETSTAT_ENDLEVEL) ) {
5328                 int old_Endlevel_sequence = Endlevel_sequence;
5329                 Endlevel_sequence = 1;
5330                 if ( pd->data_size>0 )  {
5331                         // pass pd->data to some parser function....
5332                         multi_process_bigdata( pd->data, pd->data_size );
5333                 }
5334                 Endlevel_sequence = old_Endlevel_sequence;
5335                 return;
5336         }
5337 //      mprintf((0, "Gametime = %d, Frametime = %d.\n", GameTime, FrameTime));
5338
5339         if ((byte)pd->level_num != Current_level_num)
5340         {
5341                 mprintf((0, "Got frame packet from player %d wrong level %d!\n", pd->playernum, pd->level_num));
5342                 return;
5343         }
5344
5345         TheirObj = &Objects[TheirObjnum];
5346
5347         //------------- Keep track of missed packets -----------------
5348         Players[TheirPlayernum].n_packets_got++;
5349         TotalPacketsGot++;
5350         LastPacketTime[TheirPlayernum] = timer_get_approx_seconds();
5351
5352         if  ( pd->numpackets != Players[TheirPlayernum].n_packets_got ) {
5353                 int missed_packets;
5354                 
5355                 missed_packets = pd->numpackets-Players[TheirPlayernum].n_packets_got;
5356                 if ((pd->numpackets-Players[TheirPlayernum].n_packets_got)>0)
5357                         TotalMissedPackets += pd->numpackets-Players[TheirPlayernum].n_packets_got;
5358
5359                         if ( missed_packets > 0 )       
5360                                 mprintf(( 0, "Missed %d packets from player #%d (%d total)\n", pd->numpackets-Players[TheirPlayernum].n_packets_got, TheirPlayernum, missed_packets ));
5361                         else
5362                                 mprintf( (0, "Got %d late packets from player #%d (%d total)\n", Players[TheirPlayernum].n_packets_got-pd->numpackets, TheirPlayernum, missed_packets ));
5363
5364                 #ifdef MACINTOSH
5365                 #ifdef APPLETALK_DEBUG
5366                 if (Network_game_type == APPLETALK_GAME) {
5367                         if ( missed_packets > 0 )       
5368                                 fprintf( at_fp, "Missed %d packets from player #%d (%d total)\n", pd->numpackets-Players[TheirPlayernum].n_packets_got, TheirPlayernum, missed_packets );
5369                         else
5370                                 fprintf( at_fp, "Got %d late packets from player #%d (%d total)\n", Players[TheirPlayernum].n_packets_got-pd->numpackets, TheirPlayernum, missed_packets );
5371                 }
5372                 #endif
5373                 
5374                 #ifdef IPX_DEBUG
5375                 if (Network_game_type == IPX_GAME) {
5376                         if ( missed_packets > 0 )       
5377                                 fprintf( ipx_fp, "Missed %d packets from player #%d (%d total)\n", pd->numpackets-Players[TheirPlayernum].n_packets_got, TheirPlayernum, missed_packets );
5378                         else
5379                                 fprintf( ipx_fp, "Got %d late packets from player #%d (%d total)\n", Players[TheirPlayernum].n_packets_got-pd->numpackets, TheirPlayernum, missed_packets );
5380                 }
5381                 #endif
5382                 #endif
5383
5384                 Players[TheirPlayernum].n_packets_got = pd->numpackets;
5385         }
5386
5387         //------------ Read the player's ship's object info ----------------------
5388         TheirObj->pos                           = pd->obj_pos;
5389         TheirObj->orient                        = pd->obj_orient;
5390         TheirObj->mtype.phys_info.velocity = pd->phys_velocity;
5391         TheirObj->mtype.phys_info.rotvel = pd->phys_rotvel;
5392
5393         if ((TheirObj->render_type != pd->obj_render_type) && (pd->obj_render_type == RT_POLYOBJ))
5394                 multi_make_ghost_player(TheirPlayernum);
5395
5396         obj_relink(TheirObjnum,pd->obj_segnum);
5397
5398         if (TheirObj->movement_type == MT_PHYSICS)
5399                 set_thrust_from_velocity(TheirObj);
5400
5401         //------------ Welcome them back if reconnecting --------------
5402         if (!Players[TheirPlayernum].connected) {
5403                 Players[TheirPlayernum].connected = 1;
5404
5405                 if (Newdemo_state == ND_STATE_RECORDING)
5406                         newdemo_record_multi_reconnect(TheirPlayernum);
5407
5408                 multi_make_ghost_player(TheirPlayernum);
5409
5410                 create_player_appearance_effect(&Objects[TheirObjnum]);
5411
5412                 digi_play_sample( SOUND_HUD_MESSAGE, F1_0);
5413                 
5414                 ClipRank (&NetPlayers.players[TheirPlayernum].rank);
5415
5416                 if (args_find("-norankings"))      
5417                         HUD_init_message( "'%s' %s", Players[TheirPlayernum].callsign, TXT_REJOIN );
5418                 else
5419                         HUD_init_message( "%s'%s' %s", RankStrings[NetPlayers.players[TheirPlayernum].rank],Players[TheirPlayernum].callsign, TXT_REJOIN );
5420
5421
5422                 multi_send_score();
5423         }
5424
5425         //------------ Parse the extra data at the end ---------------
5426
5427         if ( pd->data_size>0 )  {
5428                 // pass pd->data to some parser function....
5429                 multi_process_bigdata( pd->data, pd->data_size );
5430         }
5431
5432 }
5433
5434 #ifdef MACINTOSH
5435 void get_short_frame_info(ubyte *old_info, short_frame_info *new_info)
5436 {
5437         int loc = 0;
5438         
5439         new_info->type = old_info[loc];                                                                 loc++;  loc += 3;               // skip three for pad byte
5440         memcpy(&(new_info->numpackets), &(old_info[loc]), 4);                   loc += 4;
5441         new_info->numpackets = INTEL_INT(new_info->numpackets);
5442         memcpy(new_info->thepos.bytemat, &(old_info[loc]), 9);                  loc += 9;
5443         memcpy(&(new_info->thepos.xo), &(old_info[loc]), 2);                    loc += 2;
5444         memcpy(&(new_info->thepos.yo), &(old_info[loc]), 2);                    loc += 2;
5445         memcpy(&(new_info->thepos.zo), &(old_info[loc]), 2);                    loc += 2;
5446         memcpy(&(new_info->thepos.segment), &(old_info[loc]), 2);               loc += 2;
5447         memcpy(&(new_info->thepos.velx), &(old_info[loc]), 2);                  loc += 2;
5448         memcpy(&(new_info->thepos.vely), &(old_info[loc]), 2);                  loc += 2;
5449         memcpy(&(new_info->thepos.velz), &(old_info[loc]), 2);                  loc += 2;
5450         new_info->thepos.xo = INTEL_SHORT(new_info->thepos.xo);
5451         new_info->thepos.yo = INTEL_SHORT(new_info->thepos.yo);
5452         new_info->thepos.zo = INTEL_SHORT(new_info->thepos.zo);
5453         new_info->thepos.segment = INTEL_SHORT(new_info->thepos.segment);
5454         new_info->thepos.velx = INTEL_SHORT(new_info->thepos.velx);
5455         new_info->thepos.vely = INTEL_SHORT(new_info->thepos.vely);
5456         new_info->thepos.velz = INTEL_SHORT(new_info->thepos.velz);
5457
5458         memcpy(&(new_info->data_size), &(old_info[loc]), 2);            loc += 2;
5459         new_info->data_size = INTEL_SHORT(new_info->data_size);
5460         new_info->playernum = old_info[loc];                                            loc++;
5461         new_info->obj_render_type = old_info[loc];                                      loc++;
5462         new_info->level_num = old_info[loc];                                            loc++;
5463         memcpy(new_info->data, &(old_info[loc]), new_info->data_size);
5464 }
5465 #endif
5466
5467 void network_read_pdata_short_packet(short_frame_info *pd )
5468 {
5469         int TheirPlayernum;
5470         int TheirObjnum;
5471         object * TheirObj = NULL;
5472         short_frame_info new_pd;
5473
5474 // short frame info is not aligned because of shortpos.  The mac
5475 // will call totally hacked and gross function to fix this up.
5476
5477         if (Network_game_type == IPX_GAME) {
5478                 #ifndef MACINTOSH
5479                 memcpy(&new_pd, (ubyte *)pd, sizeof(short_frame_info));
5480                 #else
5481                 get_short_frame_info((ubyte *)pd, &new_pd);
5482                 #endif
5483         } else {
5484                 memcpy(&new_pd, (ubyte *)pd, sizeof(short_frame_info));
5485         }
5486
5487         TheirPlayernum = new_pd.playernum;
5488         TheirObjnum = Players[new_pd.playernum].objnum;
5489
5490         if (TheirPlayernum < 0) {
5491                 Int3(); // This packet is bogus!!
5492                 return;
5493         }
5494         if (!multi_quit_game && (TheirPlayernum >= N_players)) {
5495                 if (Network_status!=NETSTAT_WAITING)
5496                  {
5497                         Int3(); // We missed an important packet!
5498                         network_consistency_error();
5499                         return;
5500                  }
5501                 else
5502                  return;
5503         }
5504
5505    if (VerifyPlayerJoined!=-1 && TheirPlayernum==VerifyPlayerJoined)
5506          {
5507           // Hurray! Someone really really got in the game (I think).
5508       mprintf ((0,"Hurray! VPJ (%d) reset!\n",VerifyPlayerJoined));
5509       VerifyPlayerJoined=-1;
5510          }
5511
5512         if (Endlevel_sequence || (Network_status == NETSTAT_ENDLEVEL) ) {
5513                 int old_Endlevel_sequence = Endlevel_sequence;
5514                 Endlevel_sequence = 1;
5515                 if ( new_pd.data_size>0 )       {
5516                         // pass pd->data to some parser function....
5517                         multi_process_bigdata( new_pd.data, new_pd.data_size );
5518                 }
5519                 Endlevel_sequence = old_Endlevel_sequence;
5520                 return;
5521         }
5522 //      mprintf((0, "Gametime = %d, Frametime = %d.\n", GameTime, FrameTime));
5523
5524         if ((byte)new_pd.level_num != Current_level_num)
5525         {
5526                 mprintf((0, "Got frame packet from player %d wrong level %d!\n", new_pd.playernum, new_pd.level_num));
5527                 return;
5528         }
5529
5530         TheirObj = &Objects[TheirObjnum];
5531
5532         //------------- Keep track of missed packets -----------------
5533         Players[TheirPlayernum].n_packets_got++;
5534         TotalPacketsGot++;
5535         LastPacketTime[TheirPlayernum] = timer_get_approx_seconds();
5536
5537         if  ( new_pd.numpackets != Players[TheirPlayernum].n_packets_got )      {
5538                 int missed_packets;
5539         
5540                 missed_packets = new_pd.numpackets-Players[TheirPlayernum].n_packets_got;
5541                 if ((new_pd.numpackets-Players[TheirPlayernum].n_packets_got)>0)
5542                         TotalMissedPackets += new_pd.numpackets-Players[TheirPlayernum].n_packets_got;
5543
5544                 if ( missed_packets > 0 )       
5545                         mprintf( (0, "Missed %d packets from player #%d (%d total)\n", new_pd.numpackets-Players[TheirPlayernum].n_packets_got, TheirPlayernum, missed_packets ));
5546                 else
5547                         mprintf( (0, "Got %d late packets from player #%d (%d total)\n", Players[TheirPlayernum].n_packets_got-new_pd.numpackets, TheirPlayernum, missed_packets ));
5548
5549                 Players[TheirPlayernum].n_packets_got = new_pd.numpackets;
5550         }
5551
5552         //------------ Read the player's ship's object info ----------------------
5553
5554         extract_shortpos(TheirObj, &new_pd.thepos, 0);
5555
5556         if ((TheirObj->render_type != new_pd.obj_render_type) && (new_pd.obj_render_type == RT_POLYOBJ))
5557                 multi_make_ghost_player(TheirPlayernum);
5558
5559         if (TheirObj->movement_type == MT_PHYSICS)
5560                 set_thrust_from_velocity(TheirObj);
5561
5562         //------------ Welcome them back if reconnecting --------------
5563         if (!Players[TheirPlayernum].connected) {
5564                 Players[TheirPlayernum].connected = 1;
5565
5566                 if (Newdemo_state == ND_STATE_RECORDING)
5567                         newdemo_record_multi_reconnect(TheirPlayernum);
5568
5569                 multi_make_ghost_player(TheirPlayernum);
5570
5571                 create_player_appearance_effect(&Objects[TheirObjnum]);
5572
5573                 digi_play_sample( SOUND_HUD_MESSAGE, F1_0);
5574                 ClipRank (&NetPlayers.players[TheirPlayernum].rank);
5575                 
5576                 if (args_find("-norankings"))
5577                         HUD_init_message( "'%s' %s", Players[TheirPlayernum].callsign, TXT_REJOIN );
5578                 else
5579                         HUD_init_message( "%s'%s' %s", RankStrings[NetPlayers.players[TheirPlayernum].rank],Players[TheirPlayernum].callsign, TXT_REJOIN );
5580
5581
5582                 multi_send_score();
5583         }
5584
5585         //------------ Parse the extra data at the end ---------------
5586
5587         if ( new_pd.data_size>0 )       {
5588                 // pass pd->data to some parser function....
5589                 multi_process_bigdata( new_pd.data, new_pd.data_size );
5590         }
5591
5592 }
5593
5594   
5595 void network_set_power (void)
5596  {
5597   int opt=0,choice,opt_primary,opt_second,opt_power;
5598   newmenu_item m[40];
5599   
5600   opt_primary=opt;
5601   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Laser upgrade"; m[opt].value=Netgame.DoLaserUpgrade; opt++;
5602   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Super lasers"; m[opt].value=Netgame.DoSuperLaser; opt++;
5603   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Quad Lasers"; m[opt].value=Netgame.DoQuadLasers; opt++;
5604   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Vulcan cannon"; m[opt].value=Netgame.DoVulcan; opt++;
5605   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Spreadfire cannon"; m[opt].value=Netgame.DoSpread; opt++;
5606   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Plasma cannon"; m[opt].value=Netgame.DoPlasma; opt++;
5607   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Fusion cannon"; m[opt].value=Netgame.DoFusions; opt++;
5608   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Gauss cannon"; m[opt].value=Netgame.DoGauss; opt++;
5609   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Helix cannon"; m[opt].value=Netgame.DoHelix; opt++;
5610   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Phoenix cannon"; m[opt].value=Netgame.DoPhoenix; opt++;
5611   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Omega cannon"; m[opt].value=Netgame.DoOmega; opt++;
5612   
5613   opt_second=opt;   
5614   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Homing Missiles"; m[opt].value=Netgame.DoHoming; opt++;
5615   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Proximity Bombs"; m[opt].value=Netgame.DoProximity; opt++;
5616   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Smart Missiles"; m[opt].value=Netgame.DoSmarts; opt++;
5617   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Mega Missiles"; m[opt].value=Netgame.DoMegas; opt++;
5618   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Flash Missiles"; m[opt].value=Netgame.DoFlash; opt++;
5619   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Guided Missiles"; m[opt].value=Netgame.DoGuided; opt++;
5620   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Smart Mines"; m[opt].value=Netgame.DoSmartMine; opt++;
5621   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Mercury Missiles"; m[opt].value=Netgame.DoMercury; opt++;
5622   m[opt].type = NM_TYPE_CHECK; m[opt].text = "EarthShaker Missiles"; m[opt].value=Netgame.DoEarthShaker; opt++;
5623
5624   opt_power=opt;
5625   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Invulnerability"; m[opt].value=Netgame.DoInvulnerability; opt++;
5626   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Cloaking"; m[opt].value=Netgame.DoCloak; opt++;
5627   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Afterburners"; m[opt].value=Netgame.DoAfterburner; opt++;
5628   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Ammo rack"; m[opt].value=Netgame.DoAmmoRack; opt++;
5629   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Energy Converter"; m[opt].value=Netgame.DoConverter; opt++;
5630   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Headlight"; m[opt].value=Netgame.DoHeadlight; opt++;
5631   
5632   choice = newmenu_do(NULL, "Objects to allow", opt, m, NULL);
5633
5634   Netgame.DoLaserUpgrade=m[opt_primary].value; 
5635   Netgame.DoSuperLaser=m[opt_primary+1].value;
5636   Netgame.DoQuadLasers=m[opt_primary+2].value;  
5637   Netgame.DoVulcan=m[opt_primary+3].value;
5638   Netgame.DoSpread=m[opt_primary+4].value;
5639   Netgame.DoPlasma=m[opt_primary+5].value;
5640   Netgame.DoFusions=m[opt_primary+6].value;
5641   Netgame.DoGauss=m[opt_primary+7].value;
5642   Netgame.DoHelix=m[opt_primary+8].value;
5643   Netgame.DoPhoenix=m[opt_primary+9].value;
5644   Netgame.DoOmega=m[opt_primary+10].value;
5645   
5646   Netgame.DoHoming=m[opt_second].value;
5647   Netgame.DoProximity=m[opt_second+1].value;
5648   Netgame.DoSmarts=m[opt_second+2].value;
5649   Netgame.DoMegas=m[opt_second+3].value;
5650   Netgame.DoFlash=m[opt_second+4].value;
5651   Netgame.DoGuided=m[opt_second+5].value;
5652   Netgame.DoSmartMine=m[opt_second+6].value;
5653   Netgame.DoMercury=m[opt_second+7].value;
5654   Netgame.DoEarthShaker=m[opt_second+8].value;
5655
5656   Netgame.DoInvulnerability=m[opt_power].value;
5657   Netgame.DoCloak=m[opt_power+1].value;
5658   Netgame.DoAfterburner=m[opt_power+2].value;
5659   Netgame.DoAmmoRack=m[opt_power+3].value;
5660   Netgame.DoConverter=m[opt_power+4].value;     
5661   Netgame.DoHeadlight=m[opt_power+5].value;     
5662   
5663  }
5664
5665 void SetAllAllowablesTo (int on)
5666  {
5667   last_cinvul = control_invul_time = 0;   //default to zero
5668    
5669   Netgame.DoMegas=Netgame.DoSmarts=Netgame.DoFusions=Netgame.DoHelix=\
5670   Netgame.DoPhoenix=Netgame.DoCloak=Netgame.DoInvulnerability=\
5671   Netgame.DoAfterburner=Netgame.DoGauss=Netgame.DoVulcan=Netgame.DoPlasma=on;
5672
5673   Netgame.DoOmega=Netgame.DoSuperLaser=Netgame.DoProximity=\
5674   Netgame.DoSpread=Netgame.DoMercury=Netgame.DoSmartMine=Netgame.DoFlash=\
5675   Netgame.DoGuided=Netgame.DoEarthShaker=on;
5676   
5677   Netgame.DoConverter=Netgame.DoAmmoRack=Netgame.DoHeadlight=on;
5678   Netgame.DoHoming=Netgame.DoLaserUpgrade=Netgame.DoQuadLasers=on;
5679   Netgame.BrightPlayers=Netgame.invul=on;
5680  }
5681
5682 fix LastPTA;
5683 int LastKillGoal;
5684
5685 // Jeez -- mac compiler can't handle all of these on the same decl line.
5686 int opt_setpower,opt_playtime,opt_killgoal,opt_socket,opt_marker_view,opt_light,opt_show_on_map;
5687 int opt_difficulty,opt_packets,opt_short_packets, opt_bright,opt_start_invul;
5688 int opt_show_names;
5689
5690 void network_more_options_poll( int nitems, newmenu_item * menus, int * key, int citem );
5691   
5692 void network_more_game_options ()
5693  {
5694   int opt=0,i;
5695   char PlayText[80],KillText[80],srinvul[50],socket_string[5],packstring[5];
5696   newmenu_item m[21];
5697
5698   sprintf (socket_string,"%d",Network_socket);
5699   sprintf (packstring,"%d",Netgame.PacketsPerSec);
5700
5701   opt_difficulty = opt;
5702   m[opt].type = NM_TYPE_SLIDER; m[opt].value=netgame_difficulty; m[opt].text=TXT_DIFFICULTY; m[opt].min_value=0; m[opt].max_value=(NDL-1); opt++;
5703
5704   opt_cinvul = opt;
5705   sprintf( srinvul, "%s: %d %s", TXT_REACTOR_LIFE, control_invul_time*5, TXT_MINUTES_ABBREV );
5706   m[opt].type = NM_TYPE_SLIDER; m[opt].value=control_invul_time; m[opt].text= srinvul; m[opt].min_value=0; m[opt].max_value=10; opt++;
5707
5708   opt_playtime=opt;
5709   sprintf( PlayText, "Max time: %d %s", Netgame.PlayTimeAllowed*5, TXT_MINUTES_ABBREV );
5710   m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.PlayTimeAllowed; m[opt].text= PlayText; m[opt].min_value=0; m[opt].max_value=10; opt++;
5711
5712   opt_killgoal=opt;
5713   sprintf( KillText, "Kill Goal: %d kills", Netgame.KillGoal*5);
5714   m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.KillGoal; m[opt].text= KillText; m[opt].min_value=0; m[opt].max_value=10; opt++;
5715
5716   opt_start_invul=opt;
5717   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Invulnerable when reappearing"; m[opt].value=Netgame.invul; opt++;
5718         
5719   opt_marker_view = opt;
5720   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Allow camera views from Markers"; m[opt].value=Netgame.Allow_marker_view; opt++;
5721   opt_light = opt;
5722   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Indestructible lights"; m[opt].value=Netgame.AlwaysLighting; opt++;
5723
5724   opt_bright = opt;
5725   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Bright player ships"; m[opt].value=Netgame.BrightPlayers; opt++;
5726   
5727   opt_show_names=opt;
5728   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Show enemy names on HUD"; m[opt].value=Netgame.ShowAllNames; opt++;
5729
5730   opt_show_on_map=opt;
5731   m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_ON_MAP; m[opt].value=(Netgame.game_flags & NETGAME_FLAG_SHOW_MAP); opt_show_on_map=opt; opt++;
5732
5733   opt_short_packets=opt;
5734   m[opt].type = NM_TYPE_CHECK; m[opt].text = "Short packets"; m[opt].value=Netgame.ShortPackets; opt++;
5735
5736   opt_setpower = opt;
5737   m[opt].type = NM_TYPE_MENU;  m[opt].text = "Set Objects allowed..."; opt++;
5738
5739   if (Network_game_type == IPX_GAME) {
5740           m[opt].type = NM_TYPE_TEXT; m[opt].text = "Network socket"; opt++;
5741           opt_socket = opt;
5742           m[opt].type = NM_TYPE_INPUT; m[opt].text = socket_string; m[opt].text_len=4; opt++;
5743   }
5744
5745   m[opt].type = NM_TYPE_TEXT; m[opt].text = "Packets per second (2 - 20)"; opt++;
5746   opt_packets=opt;
5747   m[opt].type = NM_TYPE_INPUT; m[opt].text=packstring; m[opt].text_len=2; opt++;
5748
5749   LastKillGoal=Netgame.KillGoal;
5750   LastPTA=Netgame.PlayTimeAllowed;
5751
5752   menu:
5753
5754   ExtGameStatus=GAMESTAT_MORE_NETGAME_OPTIONS; 
5755   i = newmenu_do1( NULL, "Additional netgame options", opt, m, network_more_options_poll, 0 );
5756
5757    //control_invul_time = atoi( srinvul )*60*F1_0;
5758     control_invul_time = m[opt_cinvul].value;
5759     Netgame.control_invul_time = control_invul_time*5*F1_0*60;
5760
5761   if (i==opt_setpower)
5762    {
5763     network_set_power ();
5764     goto menu;
5765    }
5766
5767   Netgame.PacketsPerSec=atoi(packstring);
5768
5769   if (Netgame.PacketsPerSec>20)
5770         {
5771          Netgame.PacketsPerSec=20;
5772          nm_messagebox(TXT_ERROR, 1, TXT_OK, "Packet value out of range\nSetting value to 20");
5773         }
5774   if (Netgame.PacketsPerSec<2)
5775         {
5776           nm_messagebox(TXT_ERROR, 1, TXT_OK, "Packet value out of range\nSetting value to 2");
5777           Netgame.PacketsPerSec=2;      
5778         }
5779
5780   mprintf ((0,"Hey! Sending out %d packets per second\n",Netgame.PacketsPerSec));
5781
5782         if (Network_game_type == IPX_GAME) { 
5783                 if ((atoi(socket_string))!=Network_socket) {
5784                         Network_socket=atoi(socket_string);
5785                         ipx_change_default_socket( IPX_DEFAULT_SOCKET + Network_socket );
5786                 }
5787         }
5788
5789   Netgame.invul=m[opt_start_invul].value;       
5790   Netgame.BrightPlayers=m[opt_bright].value;
5791   Netgame.ShortPackets=m[opt_short_packets].value;
5792   Netgame.ShowAllNames=m[opt_show_names].value;
5793   network_AdjustMaxDataSize();
5794
5795   Netgame.Allow_marker_view=m[opt_marker_view].value;   
5796   Netgame.AlwaysLighting=m[opt_light].value;     
5797   netgame_difficulty=Difficulty_level = m[opt_difficulty].value;
5798   if (m[opt_show_on_map].value)
5799         Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP;
5800         
5801         
5802  }
5803
5804 void network_more_options_poll( int nitems, newmenu_item * menus, int * key, int citem )
5805  {
5806    menus = menus;
5807    citem = citem;      // kills compile warnings
5808    nitems = nitems;
5809    key = key;
5810
5811    if ( last_cinvul != menus[opt_cinvul].value )   {
5812         sprintf( menus[opt_cinvul].text, "%s: %d %s", TXT_REACTOR_LIFE, menus[opt_cinvul].value*5, TXT_MINUTES_ABBREV );
5813         last_cinvul = menus[opt_cinvul].value;
5814         menus[opt_cinvul].redraw = 1;
5815    }
5816   
5817   if (menus[opt_playtime].value!=LastPTA)
5818    {
5819     #ifdef SHAREWARE
5820       LastPTA=0;
5821       nm_messagebox ("Sorry",1,TXT_OK,"Registered version only!");
5822       menus[opt_playtime].value=0;
5823       menus[opt_playtime].redraw=1;
5824       return;
5825     #endif  
5826
5827     if (Game_mode & GM_MULTI_COOP)
5828      {
5829       LastPTA=0;
5830       nm_messagebox ("Sorry",1,TXT_OK,"You can't change those for coop!");
5831       menus[opt_playtime].value=0;
5832       menus[opt_playtime].redraw=1;
5833       return;
5834      }
5835
5836     Netgame.PlayTimeAllowed=menus[opt_playtime].value;
5837     sprintf( menus[opt_playtime].text, "Max Time: %d %s", Netgame.PlayTimeAllowed*5, TXT_MINUTES_ABBREV );
5838     LastPTA=Netgame.PlayTimeAllowed;
5839     menus[opt_playtime].redraw=1;
5840    }
5841   if (menus[opt_killgoal].value!=LastKillGoal)
5842    {
5843     #ifdef SHAREWARE
5844       nm_messagebox ("Sorry",1,TXT_OK,"Registered version only!");
5845       menus[opt_killgoal].value=0;
5846       menus[opt_killgoal].redraw=1;
5847       LastKillGoal=0;
5848       return;
5849          #endif         
5850
5851
5852     if (Game_mode & GM_MULTI_COOP)
5853      {
5854       nm_messagebox ("Sorry",1,TXT_OK,"You can't change those for coop!");
5855       menus[opt_killgoal].value=0;
5856       menus[opt_killgoal].redraw=1;
5857       LastKillGoal=0;
5858       return;
5859      }
5860
5861     
5862     Netgame.KillGoal=menus[opt_killgoal].value;
5863     sprintf( menus[opt_killgoal].text, "Kill Goal: %d kills", Netgame.KillGoal*5);
5864     LastKillGoal=Netgame.KillGoal;
5865     menus[opt_killgoal].redraw=1;
5866    }
5867  }
5868
5869 extern void multi_send_light (int,ubyte);
5870 extern void multi_send_light_specific (int,int,ubyte);
5871
5872 void network_send_smash_lights (int pnum) 
5873  {
5874   // send the lights that have been blown out
5875
5876   int i;
5877
5878   pnum=pnum;
5879   
5880   for (i=0;i<=Highest_segment_index;i++)
5881    if (Light_subtracted[i])
5882     multi_send_light_specific(pnum,i,Light_subtracted[i]);
5883  }
5884
5885 extern int Num_triggers;
5886 extern void multi_send_trigger_specific (char pnum,char);
5887
5888 void network_send_fly_thru_triggers (int pnum) 
5889  {
5890   // send the fly thru triggers that have been disabled
5891
5892   char i;
5893
5894   for (i=0;i<Num_triggers;i++)
5895    if (Triggers[i].flags & TF_DISABLED)
5896     multi_send_trigger_specific(pnum,i);
5897  }
5898
5899 void network_send_player_flags()
5900  {
5901   int i;
5902
5903   for (i=0;i<N_players;i++)
5904         multi_send_flags(i);
5905  }
5906
5907 void network_ping (ubyte flag,int pnum)
5908 {
5909         ubyte mybuf[2];
5910
5911         mybuf[0]=flag;
5912         mybuf[1]=Player_num;
5913
5914         if (Network_game_type == IPX_GAME)
5915                 ipx_send_packet_data( (ubyte *)mybuf, 2, NetPlayers.players[pnum].network.ipx.server, NetPlayers.players[pnum].network.ipx.node,Players[pnum].net_address );
5916         #ifdef MACINTOSH
5917         else
5918                 appletalk_send_packet_data( (ubyte *)mybuf, 2, NetPlayers.players[pnum].network.appletalk.node, NetPlayers.players[pnum].network.appletalk.net, NetPlayers.players[pnum].network.appletalk.socket);
5919         #endif
5920 }
5921
5922 extern fix PingLaunchTime,PingReturnTime;
5923
5924 void network_handle_ping_return (ubyte pnum)
5925  {
5926   if (PingLaunchTime==0 || pnum>=N_players)
5927         {
5928          mprintf ((0,"Got invalid PING RETURN from %s!\n",Players[pnum].callsign));
5929     return;
5930    }
5931   
5932   PingReturnTime=timer_get_fixed_seconds();
5933
5934   HUD_init_message ("Ping time for %s is %d ms!",Players[pnum].callsign,
5935         f2i(fixmul(PingReturnTime-PingLaunchTime,i2f(1000))));
5936   PingLaunchTime=0;
5937  }
5938         
5939 void network_send_ping (ubyte pnum)
5940  {
5941   network_ping (PID_PING_SEND,pnum);
5942  }  
5943
5944 void DoRefuseStuff (sequence_packet *their)
5945  {
5946   int i,new_player_num;
5947
5948   ClipRank (&their->player.rank);
5949         
5950   for (i=0;i<MAX_PLAYERS;i++)
5951          if (!strcmp (their->player.callsign,Players[i].callsign))
5952         {
5953                 network_welcome_player(their);
5954                         return;
5955                 }
5956   
5957    if (!WaitForRefuseAnswer)    
5958     {
5959         for (i=0;i<MAX_PLAYERS;i++)
5960                  if (!strcmp (their->player.callsign,Players[i].callsign))
5961                 {
5962                         network_welcome_player(their);
5963                                 return;
5964                         }
5965    
5966       digi_play_sample (SOUND_HUD_JOIN_REQUEST,F1_0*2);           
5967   
5968       if (Game_mode & GM_TEAM)
5969                  {
5970         
5971                                         
5972       if (!args_find("-norankings"))
5973               HUD_init_message ("%s %s wants to join",RankStrings[their->player.rank],their->player.callsign);
5974         #ifndef MACINTOSH
5975                 HUD_init_message ("%s joining. Alt-1 assigns to team %s. Alt-2 to team %s",their->player.callsign,Netgame.team_name[0],Netgame.team_name[1]);
5976                 #else
5977                 HUD_init_message ("%s joining. Opt-1 assigns to team %s. Opt-2 to team %s",their->player.callsign,Netgame.team_name[0],Netgame.team_name[1]);
5978                 #endif
5979 //                      HUD_init_message ("Alt-1 to place on team %s!",Netgame.team_name[0]);
5980 //                      HUD_init_message ("Alt-2 to place on team %s!",Netgame.team_name[1]);
5981                  }               
5982                 else    
5983                 HUD_init_message ("%s wants to join...press F6 to connect",their->player.callsign);
5984
5985            strcpy (RefusePlayerName,their->player.callsign);
5986            RefuseTimeLimit=timer_get_approx_seconds();   
5987                 RefuseThisPlayer=0;
5988                 WaitForRefuseAnswer=1;
5989          }
5990         else
5991          {      
5992         for (i=0;i<MAX_PLAYERS;i++)
5993                  if (!strcmp (their->player.callsign,Players[i].callsign))
5994                 {
5995                         network_welcome_player(their);
5996                                 return;
5997                         }
5998       
5999                 if (strcmp(their->player.callsign,RefusePlayerName))
6000                         return;
6001
6002                 if (RefuseThisPlayer)
6003                  {
6004                                 RefuseTimeLimit=0;
6005                                 RefuseThisPlayer=0;
6006                                 WaitForRefuseAnswer=0;
6007                                 if (Game_mode & GM_TEAM)
6008                                  {
6009                                         new_player_num=GetNewPlayerNumber (their);
6010                                         mprintf ((0,"Newplayernum=%d\n",new_player_num));
6011                 
6012                                         Assert (RefuseTeam==1 || RefuseTeam==2);        
6013                                 
6014                                         if (RefuseTeam==1)      
6015                                         Netgame.team_vector &=(~(1<<new_player_num));
6016                                         else
6017                                         Netgame.team_vector |=(1<<new_player_num);
6018                                         network_welcome_player(their);
6019                                         network_send_netgame_update (); 
6020                                  }
6021                                 else
6022                                         network_welcome_player(their);
6023                            return;
6024                  }
6025                                         
6026           if ((timer_get_approx_seconds()) > RefuseTimeLimit+REFUSE_INTERVAL)
6027                 {
6028                         RefuseTimeLimit=0;
6029                         RefuseThisPlayer=0;
6030                         WaitForRefuseAnswer=0;
6031                         if (!strcmp (their->player.callsign,RefusePlayerName)) {
6032                                 if (Network_game_type == IPX_GAME)
6033                                         network_dump_player(their->player.network.ipx.server,their->player.network.ipx.node, DUMP_DORK);
6034                                 #ifdef MACINTOSH
6035                                 else
6036                                         network_dump_appletalk_player(their->player.network.appletalk.node,their->player.network.appletalk.net, their->player.network.appletalk.socket, DUMP_DORK);
6037                                 #endif
6038                         }
6039                         return;
6040                 }
6041                                                         
6042     }
6043  }
6044
6045 int GetNewPlayerNumber (sequence_packet *their)
6046   {
6047          int i;
6048         
6049          their=their;
6050         
6051                 if ( N_players < MaxNumNetPlayers)
6052                         return (N_players);
6053                 
6054                 else
6055                 {
6056                         // Slots are full but game is open, see if anyone is
6057                         // disconnected and replace the oldest player with this new one
6058                 
6059                         int oldest_player = -1;
6060                         fix oldest_time = timer_get_approx_seconds();
6061
6062                         Assert(N_players == MaxNumNetPlayers);
6063
6064                         for (i = 0; i < N_players; i++)
6065                         {
6066                                 if ( (!Players[i].connected) && (LastPacketTime[i] < oldest_time))
6067                                 {
6068                                         oldest_time = LastPacketTime[i];
6069                                         oldest_player = i;
6070                                 }
6071                         }
6072             return (oldest_player);
6073           }
6074   }
6075
6076 void network_send_extras ()
6077  {
6078         Assert (Player_joining_extras>-1);
6079
6080    if (!network_i_am_master())
6081          {
6082           mprintf ((0,"Hey! I'm not the master and I was gonna send info!\n"));
6083          // Int3();     
6084          // Network_sending_extras=0;
6085          // return;
6086     }
6087
6088
6089    if (Network_sending_extras==40)
6090                 network_send_fly_thru_triggers(Player_joining_extras);
6091    if (Network_sending_extras==38)
6092         network_send_door_updates(Player_joining_extras);
6093    if (Network_sending_extras==35)
6094                 network_send_markers();
6095    if (Network_sending_extras==30 && (Game_mode & GM_MULTI_ROBOTS))
6096                 multi_send_stolen_items();
6097         if (Network_sending_extras==25 && (Netgame.PlayTimeAllowed || Netgame.KillGoal))
6098                 multi_send_kill_goal_counts();
6099    if (Network_sending_extras==20)
6100                 network_send_smash_lights(Player_joining_extras);
6101    if (Network_sending_extras==15)
6102                 network_send_player_flags();    
6103    if (Network_sending_extras==10)
6104                 multi_send_powerup_update();  
6105  //  if (Network_sending_extras==5)
6106 //              network_send_door_updates(Player_joining_extras); // twice!
6107
6108         Network_sending_extras--;
6109    if (!Network_sending_extras)
6110          Player_joining_extras=-1;
6111  }
6112
6113
6114 void network_send_naked_packet(char *buf, short len, int who)
6115 {
6116         if (!(Game_mode&GM_NETWORK)) return;
6117
6118    if (NakedPacketLen==0)
6119          {
6120            NakedBuf[0]=PID_NAKED_PDATA;
6121            NakedBuf[1]=Player_num;
6122                 NakedPacketLen=2;
6123          }
6124
6125    if (len+NakedPacketLen>MaxXDataSize)
6126     {
6127 //         mprintf ((0,"Sending a naked packet of %d bytes.\n",NakedPacketLen));
6128                 if (Network_game_type == IPX_GAME)
6129                         ipx_send_packet_data( (ubyte *)NakedBuf, NakedPacketLen, NetPlayers.players[who].network.ipx.server, NetPlayers.players[who].network.ipx.node,Players[who].net_address );
6130                 #ifdef MACINTOSH
6131                 else
6132                         appletalk_send_packet_data( (ubyte *)NakedBuf, NakedPacketLen, NetPlayers.players[who].network.appletalk.node, NetPlayers.players[who].network.appletalk.net, NetPlayers.players[who].network.appletalk.socket );
6133                 #endif
6134                 NakedPacketLen=2;
6135                 memcpy (&NakedBuf[NakedPacketLen],buf,len);     
6136                 NakedPacketLen+=len;
6137                 NakedPacketDestPlayer=who;
6138          }
6139    else
6140          {
6141                 memcpy (&NakedBuf[NakedPacketLen],buf,len);     
6142                 NakedPacketLen+=len;
6143                 NakedPacketDestPlayer=who;
6144          }
6145  }
6146
6147
6148 void network_process_naked_pdata (char *data,int len)
6149  {
6150    int pnum=data[1]; 
6151    Assert (data[0]=PID_NAKED_PDATA);
6152
6153 //   mprintf ((0,"Processing a naked packet of %d length.\n",len));
6154
6155         if (pnum < 0) {
6156            mprintf ((0,"Naked packet is bad!\n"));
6157                 Int3(); // This packet is bogus!!
6158                 return;
6159         }
6160
6161         if (!multi_quit_game && (pnum >= N_players)) {
6162                 if (Network_status!=NETSTAT_WAITING)
6163                  {
6164                         Int3(); // We missed an important packet!
6165                         network_consistency_error();
6166                         return;
6167                  }
6168                 else
6169                  return;
6170         }
6171
6172         if (Endlevel_sequence || (Network_status == NETSTAT_ENDLEVEL) ) {
6173                 int old_Endlevel_sequence = Endlevel_sequence;
6174                 Endlevel_sequence = 1;
6175                 multi_process_bigdata( data+2, len-2);
6176                 Endlevel_sequence = old_Endlevel_sequence;
6177                 return;
6178         }
6179
6180         multi_process_bigdata( data+2, len-2 );
6181  }
6182
6183 int ConnectionPacketLevel[]={0,1,1,1};
6184 int ConnectionSecLevel[]={12,3,5,7};
6185
6186 int AppletalkConnectionPacketLevel[]={0,1,0};
6187 int AppletalkConnectionSecLevel[]={10,3,8};
6188
6189 #if defined(RELEASE) && !defined(MACINTOSH)             // use the code below for mac appletalk games
6190 int network_choose_connect ()
6191  {
6192   return (1);
6193  }
6194 #else
6195 int network_choose_connect ()
6196  {
6197         newmenu_item m[16];
6198         int choice,opt=0;
6199
6200         if (Network_game_type == IPX_GAME) {  
6201                 #if 0
6202            m[opt].type = NM_TYPE_MENU;  m[opt].text = "Local Subnet"; opt++;
6203            m[opt].type = NM_TYPE_MENU;  m[opt].text = "14.4 modem over Internet"; opt++;
6204            m[opt].type = NM_TYPE_MENU;  m[opt].text = "28.8 modem over Internet"; opt++;
6205            m[opt].type = NM_TYPE_MENU;  m[opt].text = "ISDN or T1 over Internet"; opt++;
6206
6207            choice = newmenu_do1( NULL, "Choose connection type", opt, m, NULL, 0 );
6208
6209                 if (choice<0)
6210                  return (NULL);
6211
6212            Assert (choice>=0 && choice<=3);
6213    
6214                 Netgame.ShortPackets=ConnectionPacketLevel[choice];
6215                 Netgame.PacketsPerSec=ConnectionSecLevel[choice];
6216                 #endif
6217            return (1);
6218         #ifdef MACINTOSH
6219         } else {
6220            m[opt].type = NM_TYPE_MENU;  m[opt].text = "EtherTalk"; opt++;
6221            m[opt].type = NM_TYPE_MENU;  m[opt].text = "LocalTalk"; opt++;
6222            m[opt].type = NM_TYPE_MENU;  m[opt].text = "Other"; opt++;
6223         
6224            choice = newmenu_do1( NULL, "Choose connection type", opt, m, NULL, 0 );
6225
6226                 if (choice<0)
6227                  return (NULL);
6228
6229                 Network_appletalk_type = choice;
6230                 
6231                 Assert (choice>=0 && choice<=2);
6232    
6233                 Netgame.ShortPackets=AppletalkConnectionPacketLevel[choice];
6234                 Netgame.PacketsPerSec=AppletalkConnectionSecLevel[choice];
6235            return (1);
6236         #endif
6237         }
6238   return (0);   
6239  }
6240 #endif
6241
6242
6243
6244 #ifdef NETPROFILING
6245 void OpenSendLog ()
6246  {
6247   int i;
6248   SendLogFile=(FILE *)fopen ("sendlog.net","w");
6249   for (i=0;i<100;i++)
6250         TTSent[i]=0;
6251  }
6252 void OpenRecieveLog ()
6253  {
6254   int i;
6255   RecieveLogFile=(FILE *)fopen ("recvlog.net","w");
6256   for (i=0;i<100;i++)
6257         TTRecv[i]=0;
6258  }
6259 #endif
6260
6261 int GetMyNetRanking ()
6262  {
6263   int rank;
6264   int eff;
6265
6266   if (Netlife_kills+Netlife_killed==0)
6267          return (1);
6268  
6269   rank=(int) (((float)Netlife_kills/3000.0)*8.0);
6270  
6271   eff=(int)((float)((float)Netlife_kills/((float)Netlife_killed+(float)Netlife_kills))*100.0);
6272
6273   if (rank>8)
6274    rank=8;
6275   
6276   if (eff<0)
6277          eff=0;
6278  
6279   if (eff<60)
6280         rank-=((59-eff)/10);
6281         
6282   if (rank<0)
6283         rank=0;
6284   if (rank>8)
6285         rank=8;
6286  
6287   mprintf ((0,"Rank is %d (%s)\n",rank+1,RankStrings[rank+1]));
6288   return (rank+1);
6289  }
6290
6291 void ClipRank (signed char *rank)
6292  {
6293   // This function insures no crashes when dealing with D2 1.0
6294
6295  
6296   if (*rank<0 || *rank>9)
6297         *rank=0;
6298  }
6299 void network_check_for_old_version (char pnum)
6300  {  
6301   if (NetPlayers.players[pnum].version_major==1 && (NetPlayers.players[pnum].version_minor & 0x0F)==0)
6302         NetPlayers.players[pnum].rank=0;
6303  }
6304
6305 void network_request_player_names (int n)
6306  {
6307   network_send_all_info_request (PID_GAME_PLAYERS,Active_games[n].Security);
6308   NamesInfoSecurity=Active_games[n].Security;
6309  }
6310
6311 extern char already_showing_info;
6312 extern int newmenu_dotiny2( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem));
6313
6314 void network_process_names_return (char *data)
6315  {
6316         newmenu_item m[15];
6317    char mtext[15][50],temp[50];
6318         int i,t,l,gnum,num=0,count=5,numplayers;
6319    
6320    if (NamesInfoSecurity!=(*(int *)(data+1)))
6321          {
6322           mprintf ((0,"Bad security on names return!\n"));
6323           mprintf ((0,"NIS=%d data=%d\n",NamesInfoSecurity,(*(int *)(data+1))));
6324           return;
6325          }
6326
6327    numplayers=data[count]; count++;
6328
6329    if (numplayers==255)
6330          {
6331                  SurfingNet=0;  
6332                  NamesInfoSecurity=-1;
6333                  nm_messagebox(NULL, 1, "OK", "That game is refusing\nname requests.\n");
6334                  SurfingNet=1;
6335                  return;
6336          }
6337
6338    Assert (numplayers>0 && numplayers<MAX_NUM_NET_PLAYERS);
6339         
6340    for (i=0;i<12;i++)
6341         {
6342          m[i].text=&mtext[i];
6343     m[i].type=NM_TYPE_TEXT;             
6344         }
6345
6346    for (gnum=-1,i=0;i<num_active_games;i++)
6347          {
6348           if (NamesInfoSecurity==Active_games[i].Security)
6349                 {
6350                  gnum=i;
6351                  break;
6352                 }
6353          }
6354         
6355         if (gnum==-1)
6356     {
6357        SurfingNet=0;
6358                  NamesInfoSecurity=-1;
6359                  nm_messagebox(NULL, 1, "OK", "The game you have requested\nnames from is gone.\n");
6360                  SurfingNet=1;
6361                  return;
6362          }
6363  
6364    sprintf (mtext[num],"Players of game '%s':",Active_games[gnum].game_name); num++;
6365    for (i=0;i<numplayers;i++)
6366          {
6367           l=data[count++];
6368
6369      mprintf ((0,"%s\n",data+count));
6370
6371           for (t=0;t<CALLSIGN_LEN+1;t++)
6372                  temp[t]=data[count++];   
6373      if (args_find("-norankings"))      
6374              sprintf (mtext[num],"%s",temp);
6375           else
6376              sprintf (mtext[num],"%s%s",RankStrings[l],temp);
6377         
6378           num++;        
6379          }
6380
6381         if (data[count]==99)
6382         {
6383          sprintf (mtext[num++]," ");
6384          sprintf (mtext[num++],"Short packets: %s",data[count+1]?"On":"Off");
6385          sprintf (mtext[num++],"Packets Per Second: %d",data[count+2]);
6386    }
6387
6388         already_showing_info=1; 
6389         newmenu_dotiny2( NULL, NULL, num, m, NULL);
6390         already_showing_info=0; 
6391  }
6392
6393 char NameReturning=1;
6394
6395 void network_send_player_names (sequence_packet *their)
6396  {
6397   int numconnected=0,count=0,i,t;
6398   char buf[80];
6399
6400   if (!their)
6401    {
6402     mprintf ((0,"Got a player name without a return address! Get Jason\n"));
6403          return;
6404         }
6405
6406    buf[0]=PID_NAMES_RETURN; count++;
6407    (*(int *)(buf+1))=Netgame.Security; count+=4;
6408
6409    if (!NameReturning)
6410          {
6411      buf[count]=255; count++; 
6412           goto sendit;
6413          }
6414  
6415    mprintf ((0,"RealSec=%d DS=%d\n",Netgame.Security,*(int *)(buf+1)));
6416   
6417    for (i=0;i<N_players;i++)
6418          if (Players[i].connected)
6419                 numconnected++;
6420
6421    buf[count]=numconnected; count++; 
6422    for (i=0;i<N_players;i++)
6423          if (Players[i].connected)
6424           {
6425                 buf[count++]=NetPlayers.players[i].rank; 
6426                 
6427                 for (t=0;t<CALLSIGN_LEN+1;t++)
6428                  {
6429                   buf[count]=NetPlayers.players[i].callsign[t];
6430                   count++;
6431                  }
6432           }
6433
6434    buf[count++]=99;
6435         buf[count++]=Netgame.ShortPackets;              
6436         buf[count++]=Netgame.PacketsPerSec;
6437   
6438    sendit:
6439                                 ;               // empty statement allows compilation on mac which does not have the
6440                                                 // statement below and kills the compiler when there is no
6441                                                 // statement following the label "sendit"
6442            
6443    #ifndef MACINTOSH
6444            ipx_send_internetwork_packet_data((ubyte *)buf, count, their->player.network.ipx.server, their->player.network.ipx.node);
6445         #endif
6446  }
6447  
6448
6449 extern int file_exists (char *);
6450
6451 int HoardEquipped ()
6452 {
6453         static checked=-1;
6454         
6455         #ifdef WINDOWS
6456                 return 0;
6457         #endif
6458
6459         if (checked==-1)
6460         {
6461                 if (file_exists ("hoard.ham"))
6462                         checked=1;
6463                 else
6464                         checked=0;
6465         }
6466         return (checked);
6467 }
6468         
6469 #endif
6470
6471
6472
6473
6474
6475
6476
6477