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