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