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