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