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