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