]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi.cpp
added copyright header
[taylor/freespace2.git] / src / network / multi.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Network/Multi.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C file that contains high-level multiplayer functions
16  *
17  * $Log$
18  * Revision 1.5  2002/06/09 04:41:23  relnev
19  * added copyright header
20  *
21  * Revision 1.4  2002/05/27 00:40:47  theoddone33
22  * Fix net_addr vs net_addr_t
23  *
24  * Revision 1.3  2002/05/26 20:22:48  theoddone33
25  * Most of network/ works
26  *
27  * Revision 1.2  2002/05/07 03:16:47  theoddone33
28  * The Great Newline Fix
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:10  root
31  * Initial import.
32  *
33  * 
34  * 47    9/15/99 1:45a Dave
35  * Don't init joystick on standalone. Fixed campaign mode on standalone.
36  * Fixed no-score-report problem in TvT
37  * 
38  * 46    8/24/99 1:49a Dave
39  * Fixed client-side afterburner stuttering. Added checkbox for no version
40  * checking on PXO join. Made button info passing more friendly between
41  * client and server.
42  * 
43  * 45    8/22/99 5:53p Dave
44  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
45  * instead of ship designations for multiplayer players.
46  * 
47  * 44    8/22/99 1:19p Dave
48  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
49  * which d3d cards are detected.
50  * 
51  * 43    8/19/99 10:59a Dave
52  * Packet loss detection.
53  * 
54  * 42    8/16/99 4:05p Dave
55  * Big honking checkin.
56  * 
57  * 41    8/06/99 12:34a Dave
58  * Be more careful about resetting timestamps.
59  * 
60  * 40    8/04/99 2:24a Dave
61  * Fixed escort gauge ordering for dogfight.
62  * 
63  * 39    7/26/99 5:50p Dave
64  * Revised ingame join. Better? We'll see....
65  * 
66  * 38    7/08/99 10:53a Dave
67  * New multiplayer interpolation scheme. Not 100% done yet, but still
68  * better than the old way.
69  * 
70  * 37    7/06/99 4:24p Dave
71  * Mid-level checkin. Starting on some potentially cool multiplayer
72  * smoothness crap.
73  * 
74  * 36    7/03/99 5:50p Dave
75  * Make rotated bitmaps draw properly in padlock views.
76  * 
77  * 35    6/21/99 7:24p Dave
78  * netplayer pain packet. Added type E unmoving beams.
79  * 
80  * 34    6/07/99 9:51p Dave
81  * Consolidated all multiplayer ports into one.
82  * 
83  * 33    6/04/99 9:52a Dave
84  * Fixed some rendering problems.
85  * 
86  * 32    5/22/99 6:05p Dave
87  * Fixed a few localization # problems.
88  * 
89  * 31    5/22/99 5:35p Dave
90  * Debrief and chatbox screens. Fixed small hi-res HUD bug.
91  * 
92  * 30    5/14/99 1:59p Andsager
93  * Multiplayer message for subsystem cargo revealed.
94  * 
95  * 29    4/29/99 2:29p Dave
96  * Made flak work much better in multiplayer.
97  * 
98  * 28    4/28/99 11:13p Dave
99  * Temporary checkin of artillery code.
100  * 
101  * 27    4/25/99 7:43p Dave
102  * Misc small bug fixes. Made sun draw properly.
103  * 
104  * 26    4/25/99 3:02p Dave
105  * Build defines for the E3 build.
106  * 
107  * 25    4/12/99 10:07p Dave
108  * Made network startup more forgiving. Added checkmarks to dogfight
109  * screen for players who hit commit.
110  * 
111  * 24    4/09/99 2:21p Dave
112  * Multiplayer beta stuff. CD checking.
113  * 
114  * 23    3/19/99 9:51a Dave
115  * Checkin to repair massive source safe crash. Also added support for
116  * pof-style nebulae, and some new weapons code.
117  * 
118  * 23    3/11/99 5:53p Dave
119  * More network optimization. Spliced in Dell OEM planet bitmap crap.
120  * 
121  * 22    3/10/99 6:50p Dave
122  * Changed the way we buffer packets for all clients. Optimized turret
123  * fired packets. Did some weapon firing optimizations.
124  * 
125  * 21    3/09/99 6:24p Dave
126  * More work on object update revamping. Identified several sources of
127  * unnecessary bandwidth.
128  * 
129  * 20    3/08/99 7:03p Dave
130  * First run of new object update system. Looks very promising.
131  * 
132  * 19    3/02/99 4:40p Jasons
133  * Be more careful when calling server-lost-contact popup (make sure other
134  * popups aren't active)
135  * 
136  * 18    3/01/99 7:39p Dave
137  * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
138  * don't mix respawn points.
139  * 
140  * 17    2/23/99 2:29p Dave
141  * First run of oldschool dogfight mode. 
142  * 
143  * 16    2/19/99 2:55p Dave
144  * Temporary checking to report the winner of a squad war match.
145  * 
146  * 15    2/17/99 2:10p Dave
147  * First full run of squad war. All freespace and tracker side stuff
148  * works.
149  * 
150  * 14    2/12/99 6:16p Dave
151  * Pre-mission Squad War code is 95% done.
152  * 
153  * 13    2/11/99 3:08p Dave
154  * PXO refresh button. Very preliminary squad war support.
155  * 
156  * 12    1/14/99 12:48a Dave
157  * Todo list bug fixes. Made a pass at putting briefing icons back into
158  * FRED. Sort of works :(
159  * 
160  * 11    1/12/99 5:45p Dave
161  * Moved weapon pipeline in multiplayer to almost exclusively client side.
162  * Very good results. Bandwidth goes down, playability goes up for crappy
163  * connections. Fixed object update problem for ship subsystems.
164  * 
165  * 10    12/14/98 12:13p Dave
166  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
167  * Need to test now.
168  * 
169  * 9     12/03/98 5:22p Dave
170  * Ported over Freespace 1 multiplayer ships.tbl and weapons.tbl
171  * checksumming.
172  * 
173  * 8     11/19/98 4:19p Dave
174  * Put IPX sockets back in psnet. Consolidated all multiplayer config
175  * files into one.
176  * 
177  * 7     11/19/98 8:03a Dave
178  * Full support for D3-style reliable sockets. Revamped packet lag/loss
179  * system, made it receiver side and at the lowest possible level.
180  * 
181  * 6     11/17/98 11:12a Dave
182  * Removed player identification by address. Now assign explicit id #'s.
183  * 
184  * 5     11/12/98 12:13a Dave
185  * Tidied code up for multiplayer test. Put in network support for flak
186  * guns.
187  *  
188  *
189  * $NoKeywords: $
190  */
191
192 #ifndef PLAT_UNIX
193 #include <winsock.h>
194 #endif
195
196 #include "pstypes.h"
197 #include "multi.h"
198 #include "multiutil.h"
199 #include "multimsgs.h"
200 #include "psnet.h"
201 #include "linklist.h"
202 #include "object.h"
203 #include "ship.h"
204 #include "hud.h"
205 #include "timer.h"
206 #include "player.h"
207 #include "missionload.h"
208 #include "missionparse.h"
209 #include "missionshipchoice.h"
210 #include "gamesequence.h"
211 #include "freespace.h"
212 #include "osapi.h"
213 #include "math.h"
214 #include "mouse.h"
215 #include "stats.h"
216 #include "stand_gui.h"
217 #include "multi_xfer.h"
218 #include "multiui.h"
219 #include "key.h"
220 #include "multilag.h"
221 #include "multiutil.h"
222 #include "multi_ingame.h"
223 #include "bmpman.h"
224 #include "popup.h"
225 #include "cmdline.h"
226 #include "chatbox.h"
227 #include "multiteamselect.h"
228 #include "multi_data.h"
229 #include "multi_kick.h"
230 #include "multi_campaign.h"
231 #include "multi_voice.h"
232 #include "multi_team.h"
233 #include "multi_respawn.h"
234 #include "multi_pmsg.h"
235 #include "multi_endgame.h"
236 #include "missiondebrief.h"
237 #include "multi_pause.h"
238 #include "multi_obj.h"
239 #include "missiongoals.h"
240 #include "multi_log.h"
241 #include "multi_rate.h"
242 #include "hudescort.h"
243 #include "alphacolors.h"
244
245 // ----------------------------------------------------------------------------------------
246 // Basic module scope defines
247 //
248 //
249
250 // timestamp defines
251 // #define NETGAME_SEND_TIME                                                            1000                                    // time between sending netgame update packets
252 // #define STATE_SEND_TIME                                                                      1000                                    // time between sending netplayer state packets
253 // #define GAMEINFO_SEND_TIME                                                           3000                                    // time between sending game information packets
254 // #define PING_SEND_TIME                                                                       2000                                    // time between player pings
255 // #define INGAME_UPDATE_TIME                                                           1000                                    // time limit between ingame join operations
256 #define NETGAME_SEND_TIME                                                               2                                               // time between sending netgame update packets
257 #define STATE_SEND_TIME                                                                 2                                               // time between sending netplayer state packets
258 #define GAMEINFO_SEND_TIME                                                              3                                               // time between sending game information packets
259 #define PING_SEND_TIME                                                                  2                                               // time between player pings
260 #define BYTES_SENT_TIME                                                                 5                                               // every five seconds
261
262 // netplayer stuff
263 #define CULL_ZOMBIE_TIME                                                                1000                                    //      zombies are checked for at this interval (in milliseconds)
264
265 // object update stuff
266 #define SEND_POS_INTERVAL                                                               30                                              // min time in milliseconds between sending position updates
267
268 // local network buffer stuff
269 #define MAX_NET_BUFFER                                                                  (1024 * 16)                     // define and variable declaration for our local tcp buffer
270 #define NUM_REENTRANT_LEVELS                                                    3
271
272 // time (in fixed seconds) to put up dialog about no contect from server
273 #define MULTI_SERVER_MAX_TIMEOUT                                                (F1_0 * 4)                                      // after this number of milliseoncds, stop client simulation
274 #define MULTI_SERVER_MAX_TIMEOUT_LARGE                          (F1_0 * 40)                                     // done anytime not in mission
275 #define MULTI_SERVER_WAIT_TIME                                          (F1_0 * 60)                                     // wait 60 seconds to reconnect with the server
276 #define MULTI_SERVER_GONE                                                               1
277 #define MULTI_SERVER_ALIVE                                                              2
278
279 #define DISCONNECT_TIMEOUT                                                              (F1_0 * 10)                                     // 10 seconds to timeout someone who cannot connnect
280
281 // define for when to show "slow network" icon
282 #define MULTI_SERVER_SLOW_PING_TIME                                     700                                     // when average ping time to server reaches this -- display hud icon
283
284 // update times for clients ships based on object update level
285 #define MULTI_CLIENT_UPDATE_TIME                                                333
286
287 int Multi_display_netinfo = 1;
288
289 // ----------------------------------------------------------------------------------------
290 // Multiplayer vars
291 //
292 //
293
294 // net player vars              
295 net_player Net_players[MAX_PLAYERS];                                                    // array of all netplayers in the game
296 net_player *Net_player;                                                                                         // pointer to console's net_player entry
297
298 // network object management
299 ushort Next_ship_signature;                                                                             // next permanent network signature to assign to an object
300 ushort Next_asteroid_signature;                                                                 // next signature for an asteroid
301 ushort Next_non_perm_signature;                                                                 // next non-permanent network signature to assign to an object
302 ushort Next_debris_signature;                                                                           // next debris signature
303
304 // netgame vars
305 netgame_info Netgame;                                                                                           // netgame information
306 int Multi_mission_loaded = 0;                                                                           // flag, so that we dont' load the mission more than once client side
307 int Ingame_join_net_signature = -1;                                                             // signature for the player obj for use when joining ingame
308 int Multi_button_info_ok = 0;                                                                           // flag saying it is ok to apply critical button info on a client machine
309 int Multi_button_info_id = 0;                                                                           // identifier of the stored button info to be applying
310
311 // low level networking vars
312 int ADDRESS_LENGTH;                                                                                                     // will be 6 for IPX, 4 for IP
313 int PORT_LENGTH;                                                                                                                // will be 2 for IPX, 2 for IP
314 int HEADER_LENGTH;                                                                                                      // 1 byte (packet type)
315
316 // misc data
317 active_game* Active_game_head;                                                                  // linked list of active games displayed on Join screen
318 int Active_game_count;                                                                                          // for interface screens as well
319 CFILE* Multi_chat_stream;                                                                                       // for streaming multiplayer chat strings to a file
320 int Multi_has_cd = 0;                                                                                           // if this machine has a cd or not (call multi_common_verify_cd() to set this)
321 int Multi_connection_speed;                                                                             // connection speed of this machine.
322 int Multi_num_players_at_start = 0;                                                             // the # of players present (kept track of only on the server) at the very start of the mission
323 short Multi_id_num = 0;                                                                                         // for assigning player id #'s
324
325 // permanent server list
326 server_item* Game_server_head;                                                          // list of permanent game servers to be querying
327
328 // timestamp data
329 int Netgame_send_time = -1;                                                     // timestamp used to send netgame info to players before misison starts
330 int State_send_time = -1;                                                               // timestamp used to send state information to the host before a mission starts
331 int Gameinfo_send_time = -1;                                                    // timestamp used by master to send game information to clients
332 int Next_ping_time = -1;                                                                // when we should next ping all
333 int Multi_server_check_count = 0;                                       // var to keep track of reentrancy when checking server status
334 int Next_bytes_time = -1;                                                               // bytes sent
335
336 // how often each player gets updated
337 int Multi_client_update_times[MAX_PLAYERS];     // client update packet timestamp
338
339 // local network buffer data
340 LOCAL ubyte net_buffer[NUM_REENTRANT_LEVELS][MAX_NET_BUFFER];
341 LOCAL ubyte Multi_read_count;
342
343 int Multi_restr_query_timestamp = -1;
344 join_request Multi_restr_join_request;
345 net_addr_t Multi_restr_addr;                            
346 int Multi_join_restr_mode = -1;
347
348 LOCAL fix Multi_server_wait_start;                              // variable to hold start time when waiting to reestablish with server
349
350 // non API master tracker vars
351 char Multi_tracker_login[100] = "";
352 char Multi_tracker_passwd[100] = "";
353 char Multi_tracker_squad_name[100] = "";
354 int Multi_tracker_id = -1;
355 char Multi_tracker_id_string[255];
356
357 // current file checksum
358 ushort Multi_current_file_checksum = 0;
359 int Multi_current_file_length = -1;
360
361
362 // -------------------------------------------------------------------------------------------------
363 //      multi_init() is called only once, at game start-up.  Get player address + port, initialize the
364 // network players list.
365 //
366 //
367
368 void multi_init()
369 {
370         int idx;
371
372         // read in config file
373         multi_options_read_config();
374
375         Assert( Net_player == NULL );
376         Multi_id_num = 0;
377
378         // clear out all netplayers
379         memset(Net_players, 0, sizeof(net_player) * MAX_PLAYERS);
380         for(idx=0; idx<MAX_PLAYERS; idx++){
381                 Net_players[idx].reliable_socket = INVALID_SOCKET;
382         }
383
384         // initialize the local netplayer
385         Net_player = &Net_players[0];   
386         Net_player->tracker_player_id = Multi_tracker_id;
387         Net_player->player = Player;
388         Net_player->flags = 0;  
389         Net_player->s_info.xfer_handle = -1;
390         Net_player->player_id = multi_get_new_id();
391         Net_player->client_cinfo_seq = 0;
392         Net_player->client_server_seq = 0;              
393
394         // get our connection speed
395         Multi_connection_speed = multi_get_connection_speed();                  
396         
397         // initialize other stuff
398         multi_log_init();
399
400         // load up common multiplayer icons
401         multi_load_common_icons();      
402 }
403
404 // this is an important function which re-initializes any variables required in multiplayer games. 
405 // Always make sure globals you add are re-initialized here !!!!
406 void multi_vars_init()
407 {
408         // initialize this variable right away.  Used in game_level_init for init'ing the player
409         Next_ship_signature = SHIP_SIG_MIN;             
410         Next_asteroid_signature = ASTEROID_SIG_MIN;
411         Next_non_perm_signature = NPERM_SIG_MIN;   
412         Next_debris_signature = DEBRIS_SIG_MIN;
413         
414         // server-client critical stuff
415         Multi_button_info_ok = 0;
416         Multi_button_info_id = 0;
417
418         // Ingame join stuff
419         Ingame_join_net_signature = -1;
420
421         // Netgame stuff
422         Netgame.game_state = NETGAME_STATE_FORMING;     
423
424         // team select stuff
425         Multi_ts_inited = 0;    
426
427         // load send stuff
428         Multi_mission_loaded = 0;   // client side              
429
430         // restricted game stuff
431         Multi_restr_query_timestamp = -1;       
432
433         // respawn stuff        
434         Multi_server_check_count = 0;
435
436         // reentrant variable
437         Multi_read_count = 0;
438
439         // unset the "have cd" var
440         // NOTE: we unset this here because we are going to be calling multi_common_verify_cd() 
441         //       immediately after this (in multi_level_init() to re-check the status)
442         Multi_has_cd = 0;
443
444         // current file checksum
445         Multi_current_file_checksum = 0;
446         Multi_current_file_length = -1;
447
448         Active_game_head = NULL;
449         Game_server_head = NULL;
450
451         // only the server should ever care about this
452         Multi_id_num = 0;
453 }
454
455 // -------------------------------------------------------------------------------------------------
456 //      multi_level_init() is called whenever the player starts a multiplayer game
457 //
458 //
459
460 void multi_level_init() 
461 {
462         int idx;
463
464         // NETLOG
465         ml_string(NOX("multi_level_init()"));
466
467         // initialize the Net_players array
468         for(idx=0;idx<MAX_PLAYERS;idx++) {
469                 // close all sockets down just for good measure
470                 psnet_rel_close_socket(&Net_players[idx].reliable_socket);
471
472                 memset(&Net_players[idx],0,sizeof(net_player));
473                 Net_players[idx].reliable_socket = INVALID_SOCKET;
474
475                 Net_players[idx].s_info.xfer_handle = -1;
476                 Net_players[idx].p_info.team = 0;
477         }
478
479         // initialize the Players array
480         for(idx=0;idx<MAX_PLAYERS;idx++){
481                 if(Player == &Players[idx]){
482                         continue;
483                 }
484                 memset(&Players[idx],0,sizeof(player));
485         }
486
487         multi_vars_init();      
488
489         // initialize the fake lag/loss system
490 #ifdef MULTI_USE_LAG
491         multi_lag_init();
492 #endif
493
494         // initialize the kick system
495         multi_kick_init();
496
497         // initialize all file xfer stuff
498         multi_xfer_init(multi_file_xfer_notify);
499
500         // close the chatbox (if one exists)
501         chatbox_close();        
502
503         // reset the data xfer system
504         multi_data_reset();
505
506         // initialize the voice system
507         multi_voice_init();
508
509         // intialize the pause system
510         multi_pause_reset();
511
512         // initialize endgame stuff
513         multi_endgame_init();
514
515         // initialize respawning
516         multi_respawn_init();
517
518         // initialize all netgame timestamps
519    multi_reset_timestamps();
520
521         // flush psnet sockets
522         psnet_flush();
523 }
524
525 // multi_check_listen() calls low level psnet routine to see if we have a connection from a client we
526 // should accept.
527 void multi_check_listen()
528 {
529         int i;
530         net_addr_t addr;
531         PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
532
533         // call psnet routine which calls select to see if we need to check for a connect from a client
534         // by passing addr, we are telling check_for_listen to do the accept and return who it was from in
535         // addr.  The
536         sock = psnet_rel_check_for_listen(&addr);
537         if ( sock != INVALID_SOCKET ) {
538                 // be sure that my address and the server address are set correctly.
539                 if ( !psnet_same(&Psnet_my_addr, &Net_player->p_info.addr) ){
540                         Net_player->p_info.addr = Psnet_my_addr;
541                 }
542
543                 if ( !psnet_same(&Psnet_my_addr, &(Netgame.server_addr)) ){
544                         Netgame.server_addr = Psnet_my_addr;
545                 }
546
547                 // the connection was accepted in check_for_listen.  Find the netplayer whose address we connected
548                 // with and assign the socket descriptor
549                 for (i = 0; i < MAX_PLAYERS; i++ ) {
550                         if ( (Net_players[i].flags & NETINFO_FLAG_CONNECTED) && (!memcmp(&(addr.addr), &(Net_players[i].p_info.addr.addr), 6)) ) {
551                                 // mark this flag so we know he's "fully" connected
552                                 Net_players[i].flags |= NETINFO_FLAG_RELIABLE_CONNECTED;
553                                 Net_players[i].reliable_socket = sock;
554
555                                 // send player information to the joiner
556                                 send_accept_player_data( &Net_players[i], (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN)?1:0 );
557
558                                 // send a netgame update so the new client has all the necessary settings
559                                 send_netgame_update_packet();   
560
561                                 // if this is a team vs. team game, send an update
562                                 if(Netgame.type_flags & NG_TYPE_TEAM){
563                                         multi_team_send_update();
564                                 }
565
566                                 // NETLOG
567                                 ml_printf(NOX("Accepted TCP connection from %s"), Net_players[i].player == NULL ? NOX("Unknown") : Net_players[i].player->callsign);                            
568                                 break;
569                         }
570                 }
571
572                 // if we didn't find a player, close the socket
573                 if ( i == MAX_PLAYERS ) {
574                         nprintf(("Network", "Got accept on my listen socket, but unknown player.  Closing socket.\n"));
575                         psnet_rel_close_socket(&sock);
576                 }
577         }
578 }
579
580 // returns true is server hasn't been heard from in N seconds. false otherwise
581 int multi_client_server_dead()
582 {
583         fix this_time, last_time, max;
584
585         // get the last time we have heard from the server.  If greater than some default, then maybe
586         // display some icon on the HUD indicating slow network connection.  if greater than some higher
587         // max, stop simulating on the client side until we hear from the server again.
588         this_time = timer_get_fixed_seconds();
589         last_time = Netgame.server->last_heard_time;
590         // check for wrap!  must return 0
591         if ( last_time > this_time )
592                 return 0;
593
594         this_time -= last_time;
595
596         // if in mission, use the smaller timeout value.  Outside of mission, use a large one.
597         if ( MULTI_IN_MISSION ){
598                 max = MULTI_SERVER_MAX_TIMEOUT;
599         } else {
600                 max = MULTI_SERVER_MAX_TIMEOUT_LARGE;
601         }
602
603         if ( this_time > max){
604                 return 1;
605         } else {
606                 return 0;
607         }
608 }
609
610 void multi_process_incoming();          // prototype for function later in this module
611
612 // function to process network data in hopes of getting info back from server
613 int multi_client_wait_on_server()
614 {
615         int is_dead;
616
617         is_dead = multi_client_server_dead();
618
619         // if the server is back alive, tell our popup
620         if ( !is_dead ){
621                 return MULTI_SERVER_ALIVE;
622         }
623
624         // on release version -- keep popup active for 60 seconds, then bail
625 #ifdef NDEBUG
626         fix this_time = timer_get_fixed_seconds();
627         // if the timer wrapped:
628         if ( this_time < Multi_server_wait_start ) {
629                 Multi_server_wait_start = timer_get_fixed_seconds();
630                 return FALSE;
631         }
632         // check to see if timeout expired
633         this_time -= Multi_server_wait_start;
634         if ( this_time > MULTI_SERVER_WAIT_TIME ){
635                 return MULTI_SERVER_GONE;
636         }
637 #endif
638
639         return FALSE;
640 }
641
642 // function called by multiplayer clients to stop simulating when they have not heard from the server
643 // in a while.
644 void multi_client_check_server()
645 {
646         int rval;
647
648         Assert( MULTIPLAYER_CLIENT );   
649
650         // this function can get called while in the popup code below.  So we include this check as a
651         // reentrancy check.
652         if ( Multi_server_check_count )
653                 return;
654
655         // make sure we have a valid server
656         if(Netgame.server == NULL){
657                 return;
658         }
659
660         Multi_server_check_count++;
661         if(multi_client_server_dead()){
662                 Netgame.flags |= NG_FLAG_SERVER_LOST;
663         } else {
664                 Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
665         }
666
667         if(Netgame.flags & NG_FLAG_SERVER_LOST) {
668                 if(!(Game_mode & GM_IN_MISSION) && !popup_active()){    
669                         // need to start a popup
670                         Multi_server_wait_start = timer_get_fixed_seconds();
671                         rval = popup_till_condition( multi_client_wait_on_server, XSTR("Cancel",641), XSTR("Contact lost with server.  Stopping simulation until contact reestablished.  Press Cancel to exit game.",642) );
672                         
673                         if ( !rval || (rval == MULTI_SERVER_GONE) ) {                           
674                                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);                                                              
675                         }
676                         Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
677                 }
678         }
679
680         Multi_server_check_count--;
681 }
682
683
684 // -------------------------------------------------------------------------------------------------
685 //      process_packet_normal() will determine what sort of packet it is, and send it to the appropriate spot.
686 //      Prelimiary verification of the magic number and checksum are done here.  
687 //
688
689 void process_packet_normal(ubyte* data, header *header_info)
690 {
691         switch ( data[0] ) {
692
693                 case JOIN:
694                         process_join_packet(data, header_info);
695                         break;
696
697                 case GAME_CHAT:
698                         process_game_chat_packet( data, header_info );
699                         break;
700
701                 case NOTIFY_NEW_PLAYER:
702                         process_new_player_packet(data, header_info);
703                         break;
704
705                 case HUD_MSG:
706                         process_hud_message(data, header_info);
707                         break;
708
709                 case MISSION_MESSAGE:
710                         process_mission_message_packet( data, header_info );
711                         break;
712
713                 case LEAVE_GAME:
714                         process_leave_game_packet(data, header_info);
715                         break;
716
717                 case GAME_QUERY:
718                         process_game_query(data, header_info);
719                         break;
720
721                 case GAME_ACTIVE:
722                         process_game_active_packet(data, header_info);
723                         break;
724
725                 case GAME_INFO:
726                         process_game_info_packet( data, header_info );
727                         break;          
728
729                 case SECONDARY_FIRED_AI:
730                         process_secondary_fired_packet(data, header_info, 0);
731                         break;          
732
733                 case SECONDARY_FIRED_PLR:
734                         process_secondary_fired_packet(data, header_info, 1);
735                         break;
736
737                 case COUNTERMEASURE_FIRED:
738                         process_countermeasure_fired_packet( data, header_info );
739                         break;          
740
741                 case FIRE_TURRET_WEAPON:
742                         process_turret_fired_packet( data, header_info );
743                         break;
744
745                 case GAME_UPDATE:
746                         process_netgame_update_packet( data, header_info );
747                         break;
748
749                 case UPDATE_DESCRIPT:
750                         process_netgame_descript_packet( data, header_info );
751                         break;
752
753                 case NETPLAYER_UPDATE:
754                         process_netplayer_update_packet( data, header_info );
755                         break;
756
757                 case ACCEPT :
758                         process_accept_packet(data, header_info);
759                         break;                          
760
761                 case OBJECT_UPDATE:
762                         multi_oo_process_update(data, header_info);
763                         break;
764
765                 case SHIP_KILL:
766                         process_ship_kill_packet( data, header_info );
767                         break;
768
769                 case WING_CREATE:
770                         process_wing_create_packet( data, header_info );
771                         break;
772                         
773                 case SHIP_CREATE:
774                         process_ship_create_packet( data, header_info );
775                         break;
776
777                 case SHIP_DEPART:
778                         process_ship_depart_packet( data, header_info );
779                         break;
780
781                 case MISSION_LOG_ENTRY:
782                         process_mission_log_packet( data, header_info );
783                         break;          
784
785                 case PING:
786                         process_ping_packet(data, header_info);
787                         break;
788
789                 case PONG:
790                         process_pong_packet(data, header_info);
791                         break;          
792
793                 case XFER_PACKET:
794                         Assert(header_info->id >= 0);
795                         int np_index;
796                         PSNET_SOCKET_RELIABLE sock;
797                         sock = INVALID_SOCKET;
798
799                         // if I'm the server of the game, find out who this came from                   
800                         if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
801                                 np_index = find_player_id(header_info->id);
802                                 if(np_index >= 0){
803                                         sock = Net_players[np_index].reliable_socket;
804                                 }
805                         }
806                         // otherwise always use my own socket
807                         else if(Net_player != NULL){
808                                 sock = Net_player->reliable_socket;
809                         }
810                         
811                         header_info->bytes_processed = multi_xfer_process_packet(data + HEADER_LENGTH, sock) + HEADER_LENGTH;
812                         break;
813
814                 case MISSION_REQUEST:
815                         process_mission_request_packet(data,header_info);
816                         break;
817
818                 case MISSION_ITEM:
819                         process_mission_item_packet(data,header_info);
820                         break;          
821
822                 case MULTI_PAUSE_REQUEST:
823                         process_multi_pause_packet(data, header_info);
824                         break;          
825
826                 case INGAME_NAK:
827                         process_ingame_nak(data, header_info);
828                         break;
829
830                 case SHIPS_INGAME_PACKET:
831                         process_ingame_ships_packet(data, header_info);
832                         break;
833
834                 case WINGS_INGAME_PACKET:
835                         process_ingame_wings_packet(data, header_info);
836                         break;
837
838                 case MISSION_END:
839                         process_endgame_packet(data, header_info);
840                         break;
841                 
842                 case OBSERVER_UPDATE:
843                         process_observer_update_packet(data, header_info);
844                         break;
845
846                 case NETPLAYER_SLOTS_P:
847                         process_netplayer_slot_packet(data, header_info);
848                         break;
849
850                 case SHIP_STATUS_CHANGE:
851                         process_ship_status_packet(data, header_info);
852                         break;
853
854                 case PLAYER_ORDER_PACKET:
855                         process_player_order_packet(data, header_info);
856                         break;
857
858                 case INGAME_SHIP_UPDATE:
859                         process_ingame_ship_update_packet(data, header_info);
860                         break;
861
862                 case INGAME_SHIP_REQUEST:
863                         process_ingame_ship_request_packet(data, header_info);
864                         break;
865                 
866                 case FILE_SIG_INFO:
867                         process_file_sig_packet(data, header_info);
868                         break;
869
870                 case RESPAWN_NOTICE:
871                         multi_respawn_process_packet(data,header_info);                 
872                         break;
873
874                 case SUBSYSTEM_DESTROYED:
875                         process_subsystem_destroyed_packet( data, header_info );
876                         break;
877
878                 case LOAD_MISSION_NOW :
879                         process_netplayer_load_packet(data, header_info);
880                         break;
881
882                 case FILE_SIG_REQUEST :
883                         process_file_sig_request(data, header_info);
884                         break;
885
886                 case JUMP_INTO_GAME:
887                         process_jump_into_mission_packet(data, header_info);
888                         break;          
889
890                 case CLIENT_REPAIR_INFO:
891                         process_repair_info_packet(data,header_info);
892                         break;
893
894                 case MISSION_SYNC_DATA:
895                         process_mission_sync_packet(data,header_info);
896                         break;
897
898                 case STORE_MISSION_STATS:
899                         process_store_stats_packet(data, header_info);
900                         break;
901
902                 case DEBRIS_UPDATE:
903                         process_debris_update_packet(data, header_info);
904                         break;          
905
906                 case SHIP_WSTATE_CHANGE:
907                         process_ship_weapon_change( data, header_info );
908                         break;
909
910                 case WSS_UPDATE_PACKET:
911                         process_wss_update_packet(data, header_info);
912                         break;
913
914                 case WSS_REQUEST_PACKET:
915                         process_wss_request_packet( data, header_info );
916                         break;  
917
918                 case FIRING_INFO:
919                         process_firing_info_packet( data, header_info );
920                         break;          
921
922                 case CARGO_REVEALED:
923                         process_cargo_revealed_packet( data, header_info);
924                         break;          
925
926                 case SUBSYS_CARGO_REVEALED:
927                         process_subsystem_cargo_revealed_packet( data, header_info);
928                         break;          
929
930                 case MISSION_GOAL_INFO:
931                         process_mission_goal_info_packet(data, header_info);
932                         break;
933
934                 case KICK_PLAYER:
935                         process_player_kick_packet(data, header_info);
936                         break;
937
938                 case PLAYER_SETTINGS:
939                         process_player_settings_packet(data, header_info);
940                         break;
941
942                 case DENY:
943                         process_deny_packet(data, header_info);
944                         break;
945
946                 case POST_SYNC_DATA:
947                         process_post_sync_data_packet(data, header_info);
948                         break;
949
950                 case WSS_SLOTS_DATA:
951                         process_wss_slots_data_packet(data,header_info);
952                         break;
953
954                 case SHIELD_EXPLOSION:
955                         process_shield_explosion_packet( data, header_info );
956                         break;
957
958                 case PLAYER_STATS:
959                         process_player_stats_block_packet(data, header_info);
960                         break;
961
962                 case SLOT_UPDATE:
963                         process_pslot_update_packet(data,header_info);
964                         break;
965
966                 case AI_INFO_UPDATE:
967                         process_ai_info_update_packet( data, header_info );
968                         break;          
969
970                 case CAMPAIGN_UPDATE :
971                         multi_campaign_process_update(data,header_info);
972                         break;
973
974                 case CAMPAIGN_UPDATE_INGAME:
975                         multi_campaign_process_ingame_start(data,header_info);
976                         break;
977
978                 case VOICE_PACKET :
979                         multi_voice_process_packet(data,header_info);
980                         break;
981
982                 case TEAM_UPDATE :
983                         multi_team_process_packet(data,header_info);
984                         break;
985
986                 case ASTEROID_INFO:
987                         process_asteroid_info(data, header_info);
988                         break;          
989
990                 case HOST_RESTR_QUERY:
991                         process_host_restr_packet(data, header_info);
992                         break;
993
994                 case OPTIONS_UPDATE:
995                         multi_options_process_packet(data,header_info);
996                         break;
997
998                 case SQUADMSG_PLAYER:
999                         multi_msg_process_squadmsg_packet(data,header_info);
1000                         break;
1001
1002                 case NETGAME_END_ERROR:
1003                         process_netgame_end_error_packet(data,header_info);
1004                         break;
1005
1006                 case COUNTERMEASURE_SUCCESS:
1007                         process_countermeasure_success_packet( data, header_info );
1008                         break;
1009
1010                 case CLIENT_UPDATE:
1011                         process_client_update_packet(data, header_info);
1012                         break;
1013
1014                 case COUNTDOWN:
1015                         process_countdown_packet(data, header_info);
1016                         break;
1017
1018                 case DEBRIEF_INFO:
1019                         process_debrief_info( data, header_info );
1020                         break;
1021
1022                 case ACCEPT_PLAYER_DATA:
1023                         process_accept_player_data( data, header_info );
1024                         break;                          
1025
1026                 case HOMING_WEAPON_UPDATE:
1027                         process_homing_weapon_info( data, header_info );
1028                         break;          
1029
1030                 case EMP_EFFECT:
1031                         process_emp_effect(data, header_info);
1032                         break;
1033
1034                 case REINFORCEMENT_AVAIL:
1035                         process_reinforcement_avail( data, header_info );
1036                         break;
1037
1038                 case CHANGE_IFF:
1039                         process_change_iff_packet(data, header_info);
1040                         break;
1041
1042                 case PRIMARY_FIRED_NEW:
1043                         process_NEW_primary_fired_packet(data, header_info);
1044                         break;
1045
1046                 case COUNTERMEASURE_NEW:
1047                         process_NEW_countermeasure_fired_packet(data, header_info);
1048                         break;
1049
1050                 case BEAM_FIRED:
1051                         process_beam_fired_packet(data, header_info);
1052                         break;          
1053                         
1054                 case SW_STD_QUERY:
1055                         process_sw_query_packet(data, header_info);
1056                         break;
1057
1058                 case EVENT_UPDATE:
1059                         process_event_update_packet(data, header_info);
1060                         break;
1061
1062                 case OBJECT_UPDATE_NEW:                 
1063                         multi_oo_process_update(data, header_info);
1064                         break;
1065
1066                 case WEAPON_DET:
1067                         process_weapon_detonate_packet(data, header_info);
1068                         break;
1069
1070                 case FLAK_FIRED:
1071                         process_flak_fired_packet(data, header_info);
1072                         break;
1073
1074                 case NETPLAYER_PAIN:
1075                         process_player_pain_packet(data, header_info);
1076                         break;
1077
1078                 case LIGHTNING_PACKET:
1079                         process_lightning_packet(data, header_info);
1080                         break;
1081
1082                 case BYTES_SENT:
1083                         process_bytes_recvd_packet(data, header_info);
1084                         break;
1085
1086                 case TRANSFER_HOST:
1087                         process_host_captain_change_packet(data, header_info);
1088                         break;
1089
1090                 case SELF_DESTRUCT:
1091                         process_self_destruct_packet(data, header_info);
1092                         break;
1093
1094                 default:
1095                         nprintf(("Network", "Received packet with unknown type %d\n", data[0] ));
1096                         header_info->bytes_processed = 10000;
1097                         break;
1098
1099         } // end switch
1100 }
1101
1102
1103
1104 // Takes a bunch of messages, check them for validity,
1105 // and pass them to multi_process_data. 
1106 //  --------------------^
1107 // this should be process_packet() I think, or with the new code
1108 // process_tracker_packet() as defined in MultiTracker.[h,cpp]
1109 void multi_process_bigdata(ubyte *data, int len, net_addr_t *from_addr, int reliable)
1110 {
1111         int type, bytes_processed;
1112         int player_num;
1113         header header_info;
1114         ubyte *buf;     
1115
1116         // the only packets we will process from an unknown player are GAME_QUERY, GAME_INFO, JOIN, PING, PONG, ACCEPT, and GAME_ACTIVE packets
1117         player_num = find_player(from_addr);            
1118
1119         // find the player who sent the message and mark the last_heard time for this player
1120         // check to see if netplayer is null (it may be in cases such as getting lists of games from the tracker)
1121         if(player_num >= 0){
1122                 Net_players[player_num].last_heard_time = timer_get_fixed_seconds();
1123         }
1124
1125         // store fields that were passed along in the message
1126         // store header information that was captured from the network-layer header
1127         memcpy(header_info.addr, from_addr->addr, 6);
1128         memcpy(header_info.net_id, from_addr->net_id, 4);
1129         header_info.port = from_addr->port;     
1130         if(player_num >= 0){
1131                 header_info.id = Net_players[player_num].player_id;
1132         } else {
1133                 header_info.id = -1;
1134         }   
1135
1136         bytes_processed = 0;
1137         while( (bytes_processed >= 0) && (bytes_processed < len) )  {
1138
1139       buf = &(data[bytes_processed]);
1140
1141       type = buf[0];
1142
1143                 // if its coming from an unknown source, there are only certain packets we will actually process
1144                 if((player_num == -1) && !multi_is_valid_unknown_packet((ubyte)type)){
1145                         return ;
1146                 }               
1147
1148                 if ( (type<0) || (type > MAX_TYPE_ID )) {
1149                         nprintf( ("Network", "multi_process_bigdata: Invalid packet type %d!\n", type ));
1150                         return;
1151                 }               
1152
1153                 // perform any special processing checks here           
1154                 process_packet_normal(buf,&header_info);
1155                  
1156                 // MWA -- magic number was removed from header on 8/4/97.  Replaced with bytes_processed
1157                 // variable which gets stuffed whenever a packet is processed.
1158                 bytes_processed += header_info.bytes_processed;
1159         }
1160
1161         // if this is not reliable data and we have a valid player
1162         if(Net_player != NULL){
1163                 if(!MULTIPLAYER_MASTER && !reliable && (Game_mode & GM_IN_MISSION)){
1164                         Net_player->cl_bytes_recvd += len;
1165                 }
1166         }
1167 }
1168
1169 // process all reliable socket details
1170 void multi_process_reliable_details()
1171 {
1172         int idx;
1173         int sock_status;
1174
1175         // run reliable sockets
1176 #ifdef PSNET2
1177         psnet_rel_work();
1178 #endif
1179         
1180         // server operations
1181         if ( MULTIPLAYER_MASTER ){
1182                 // listen for new reliable socket connections
1183                 multi_check_listen();           
1184
1185                 // check for any broken sockets and delete any players
1186                 for(idx=0; idx<MAX_PLAYERS; idx++){
1187                         // players who _should_ be validly connected
1188                         if((idx != MY_NET_PLAYER_NUM) && MULTI_CONNECTED(Net_players[idx])){                            
1189                                 // if this guy's socket is broken or disconnected, kill him
1190                                 sock_status = psnet_rel_get_status(Net_players[idx].reliable_socket);
1191                                 if((sock_status == RNF_UNUSED) || (sock_status == RNF_BROKEN) || (sock_status == RNF_DISCONNECTED)){
1192                                         ml_string("Shutting down rel socket because of disconnect!");
1193                                         delete_player(idx);
1194                                 }
1195
1196                                 // if we're still waiting for this guy to connect on his reliable socket and he's timed out, boot him
1197                                 if(Net_players[idx].s_info.reliable_connect_time != -1){
1198                                         // if he's connected
1199                                         if(Net_players[idx].reliable_socket != INVALID_SOCKET){
1200                                                 Net_players[idx].s_info.reliable_connect_time = -1;
1201                                         } 
1202                                         // if he's timed out
1203                                         else if(((time(NULL) - Net_players[idx].s_info.reliable_connect_time) > MULTI_RELIABLE_CONNECT_WAIT) && (Net_players[idx].reliable_socket == INVALID_SOCKET)){
1204                                                 ml_string("Player timed out while connecting on reliable socket!");
1205                                                 delete_player(idx);
1206                                         }
1207                                 }                       
1208                         }
1209                 }
1210         }       
1211         // clients should detect broken sockets
1212         else {
1213                 extern unsigned int Serverconn;
1214                 if(Serverconn != 0xffffffff){
1215                         int status = psnet_rel_get_status(Serverconn);
1216                         if(status == RNF_BROKEN){
1217                                 mprintf(("CLIENT SOCKET DISCONNECTED"));
1218
1219                                 // quit the game
1220                                 if(!multi_endgame_ending()){
1221                                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);
1222                                 }
1223                         }
1224                 }
1225         }
1226 }
1227
1228 // multi_process_incoming reads incoming data off the unreliable and reliable ports and sends
1229 // the data to process_big_data
1230 void multi_process_incoming()
1231 {
1232         int size;
1233         ubyte *data, *savep;
1234         net_addr_t from_addr;   
1235
1236         Assert( Multi_read_count < NUM_REENTRANT_LEVELS );
1237         savep = net_buffer[Multi_read_count];
1238
1239         Multi_read_count++;
1240
1241         data = savep;
1242
1243         // get the other net players data
1244         while( (size = psnet_get(data, &from_addr))>0 ) {
1245                 // ingame joiners will ignore UDP packets until they are have picked a ship and are in the mission
1246                 if( (Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Net_player->state != NETPLAYER_STATE_INGAME_SHIP_SELECT) ){
1247                         //nprintf(("Network","Tossing UDP like a good little ingame joiner...\n"));
1248                 } 
1249                 // otherwise process incoming data normally
1250                 else {
1251                         multi_process_bigdata(data, size, &from_addr, 0);
1252                 }
1253         } // end while
1254
1255         // read reliable sockets for data
1256         data = savep;
1257         int idx;
1258
1259         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1260                 for (idx=0;idx<MAX_PLAYERS;idx++) {
1261                         if((Net_players[idx].flags & NETINFO_FLAG_CONNECTED) && (Net_player != NULL) && (Net_player->player_id != Net_players[idx].player_id)){
1262                                 while( (size = psnet_rel_get(Net_players[idx].reliable_socket, data, MAX_NET_BUFFER)) > 0){
1263                                         multi_process_bigdata(data, size, &Net_players[idx].p_info.addr, 1);
1264                                 }
1265                         }
1266                 }
1267         } else {
1268                 // if I'm not the master of the game, read reliable data from my connection with the server
1269                 if((Net_player->reliable_socket != INVALID_SOCKET) && (Net_player->reliable_socket != 0)){
1270                         while( (size = psnet_rel_get(Net_player->reliable_socket,data, MAX_NET_BUFFER)) > 0){                           
1271                                 multi_process_bigdata(data, size, &Netgame.server_addr, 1);
1272                         }
1273                 }
1274         }
1275                 
1276         Multi_read_count--;
1277 }
1278
1279 // -------------------------------------------------------------------------------------------------
1280 //      multi_do_frame() is called once per game loop do update all the multiplayer objects, and send
1281 // the player data to all the other net players.
1282 //
1283 //
1284
1285 int eye_tog = 1;
1286 DCF(eye_tog, "")
1287 {
1288         eye_tog = !eye_tog;
1289         if(eye_tog){
1290                 dc_printf("proper eye stuff on\n");
1291         } else {
1292                 dc_printf("proper eye stuff off\n");
1293         }
1294 }
1295
1296 void multi_do_frame()
1297 {       
1298         PSNET_TOP_LAYER_PROCESS();
1299
1300         // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1301         // function calls
1302         if((Net_player != NULL) && eye_tog){
1303                 player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1304         }
1305
1306         // send all buffered packets from the previous frame
1307         multi_io_send_buffered_packets();
1308
1309         // datarate tracking
1310         multi_rate_process();
1311
1312         // always process any pending endgame details
1313         multi_endgame_process();                
1314
1315         // process all reliable socket details, including :
1316         // 1.) Listening for new pending reliable connections (server)
1317         // 2.) Checking for broken sockets (server/client)
1318         // 3.) Checking for clients who haven't fully connected
1319         multi_process_reliable_details();       
1320
1321         // get the other net players data
1322         multi_process_incoming();               
1323
1324         // process object update datarate stuff (for clients and server both)
1325         multi_oo_rate_process();
1326
1327         // clients should check when last time they heard from sever was -- if too long, then
1328         // pause the simulation so wait for it to possibly come back
1329         if ( (MULTIPLAYER_CLIENT) && (Net_player->flags & NETINFO_FLAG_CONNECTED) ){
1330                 multi_client_check_server();
1331         }
1332
1333         // everybody pings all the time 
1334         if((Next_ping_time < 0) || ((time(NULL) - Next_ping_time) > PING_SEND_TIME) ){
1335                 if( (Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
1336                         send_netplayer_update_packet();
1337                 }
1338                 
1339                 // ping everyone
1340                 multi_ping_send_all();
1341                 Next_ping_time = time(NULL);            
1342         }       
1343         
1344         // if I am the master, and we are not yet actually playing the mission, send off netgame
1345         // status to all other players in the game.  If I am not the master of the game, and we
1346         // are not in the game, then send out my netplayer status to the host
1347         if ( (Net_player->flags & NETINFO_FLAG_CONNECTED) && !(Game_mode & GM_IN_MISSION)){     
1348                 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {                     
1349                         if ( (Netgame_send_time < 0) || ((time(NULL) - Netgame_send_time) > NETGAME_SEND_TIME) ) {
1350                                 send_netgame_update_packet();                           
1351                                 
1352                                 Netgame_send_time = time(NULL);
1353                         }               
1354                 } else {
1355                         if ( (State_send_time < 0) || ((time(NULL) - State_send_time) > STATE_SEND_TIME) ){
1356                                 // observers shouldn't send an update state packet
1357                                 if ( !(Net_player->flags & NETINFO_FLAG_OBSERVER) ){
1358                                         send_netplayer_update_packet();
1359                                 }                               
1360                                 
1361                                 State_send_time = time(NULL);
1362                         }
1363                 }
1364         }
1365         else if ( (Net_player->flags & NETINFO_FLAG_CONNECTED) && (Game_mode & GM_IN_MISSION) ) {       
1366                 // if I am connected and am in the mission, do things that need to be done on a regular basis
1367                 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
1368                         if ( (Gameinfo_send_time < 0) || ((time(NULL) - Gameinfo_send_time) > GAMEINFO_SEND_TIME)){
1369                                 send_game_info_packet();
1370                                 
1371                                 Gameinfo_send_time = time(NULL);
1372                         }
1373                         
1374                         // for any potential respawns
1375                         multi_respawn_handle_invul_players();
1376                         multi_respawn_check_ai();
1377
1378                         // for any potential ingame joiners
1379                         multi_handle_ingame_joiners();
1380                 } else {
1381                         // the clients need to do some processing of stuff as well                      
1382                 }
1383         }
1384
1385         // check to see if we're waiting on confirmation for a restricted ingame join
1386         if(Multi_restr_query_timestamp != -1){
1387                 // if it has elapsed, unset the ingame join flag
1388                 if(timestamp_elapsed(Multi_restr_query_timestamp)){
1389                         Multi_restr_query_timestamp = -1;
1390                         Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);             
1391                 }       
1392         }
1393
1394         // while in the mission, send my PlayerControls to the host so that he can process
1395         // my movement
1396         if ( Game_mode & GM_IN_MISSION ) {
1397                 // tickers
1398                 extern void oo_update_time();
1399                 oo_update_time();
1400
1401
1402                 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){                                    
1403                         if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1404                                 // if the rate limiting system says its ok
1405                                 if(multi_oo_cirate_can_send()){
1406                                         // send my observer position/object update
1407                                         send_observer_update_packet();
1408                                 }
1409                         } else if ( !(Player_ship->flags & SF_DEPARTING ) ){                            
1410                                 // if the rate limiting system says its ok
1411                                 if(multi_oo_cirate_can_send()){
1412                                         // use the new method
1413                                         multi_oo_send_control_info();
1414                                 }                               
1415                         }
1416
1417                         // bytes received info
1418                         if( (Next_bytes_time < 0) || ((time(NULL) - Next_bytes_time) > BYTES_SENT_TIME) ){
1419                                 if(Net_player != NULL){
1420                                         send_bytes_recvd_packet(Net_player);
1421
1422                                         // reset bytes recvd
1423                                         Net_player->cl_bytes_recvd = 0;
1424                                 }
1425
1426                                 // reset timestamp
1427                                 Next_bytes_time = time(NULL);                           
1428                         }
1429                 } else {                        
1430                         // sending new objects from here is dependent on having objects only created after
1431                         // the game is done moving the objects.  I think that I can enforce this.                               
1432                         multi_oo_process();                     
1433
1434                         // evaluate whether the time limit has been reached or max kills has been reached
1435                         // Commented out by Sandeep 4/12/98, was causing problems with testing.
1436                         if( ((f2fl(Netgame.options.mission_time_limit) > 0.0f) && (Missiontime > Netgame.options.mission_time_limit)) ||
1437                                  multi_kill_limit_reached() ) {
1438
1439                                 // make sure we don't do this more than once
1440                                 if(Netgame.game_state == NETGAME_STATE_IN_MISSION){                             
1441                                         multi_handle_end_mission_request();                                                                     
1442                                 }
1443                         }                       
1444                 }                       
1445         }
1446
1447         // periodically send a client update packet to all clients
1448         if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1449                 int idx;
1450                 for(idx=0;idx<MAX_PLAYERS;idx++){
1451                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
1452                                 if((Multi_client_update_times[idx] < 0) || timestamp_elapsed_safe(Multi_client_update_times[idx], 1000)){
1453                                         
1454                                         send_client_update_packet(&Net_players[idx]);
1455                                         
1456                                         Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1457                                 }
1458                         }
1459                 }
1460         }       
1461
1462         // process any kicked player details
1463         multi_kick_process();
1464
1465         // do any file xfer details
1466         multi_xfer_do();
1467
1468         // process any player data details (wav files, pilot pics, etc)
1469         multi_data_do();
1470
1471         // do any voice details
1472         multi_voice_process();
1473
1474         // process any player messaging details
1475         multi_msg_process();            
1476         
1477         // if on the standalone, do any gui stuff
1478         if(Game_mode & GM_STANDALONE_SERVER){
1479                 std_do_gui_frame();
1480         }       
1481
1482         // dogfight nonstandalone players should recalc the escort list every frame
1483         if(!(Game_mode & GM_STANDALONE_SERVER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && MULTI_IN_MISSION){
1484                 hud_setup_escort_list(0);
1485         }
1486 }
1487
1488 // -------------------------------------------------------------------------------------------------
1489 //      multi_pause_do_frame() is called once per game loop do update all the multiplayer objects, and send
1490 // the player data to all the other net players when the multiplayer game is paused. It only will do 
1491 // checking for a few specialized packets (MULTI_UNPAUSE, etc)
1492 //
1493
1494 void multi_pause_do_frame()
1495 {
1496         PSNET_TOP_LAYER_PROCESS();
1497
1498         // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1499         // function calls
1500         // if((Net_player != NULL) && eye_tog){
1501                 // player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1502         // }
1503
1504         // send all buffered packets from the previous frame
1505         multi_io_send_buffered_packets();
1506
1507         // always process any pending endgame details
1508         multi_endgame_process();                
1509
1510         // process all reliable socket details, including :
1511         // 1.) Listening for new pending reliable connections (server)
1512         // 2.) Checking for broken sockets (server/client)
1513         // 3.) Checking for clients who haven't fully connected
1514         multi_process_reliable_details();       
1515
1516         // these timestamps and handlers shoul be evaluated in the pause state
1517         if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
1518                 if ( (Gameinfo_send_time < 0) || ((time(NULL) - Gameinfo_send_time) > GAMEINFO_SEND_TIME) ){
1519                         send_game_info_packet();
1520                         
1521                         Gameinfo_send_time = time(NULL);
1522                 }                               
1523         }
1524
1525         // everybody pings all the time
1526         if((Next_ping_time < 0) || ((time(NULL) - Next_ping_time) > PING_SEND_TIME) ){
1527                 multi_ping_send_all();
1528                 
1529                 Next_ping_time = time(NULL);
1530         }
1531
1532         // periodically send a client update packet to all clients
1533         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1534                 int idx;
1535
1536                 for(idx=0;idx<MAX_PLAYERS;idx++){
1537                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){                     
1538                                 if((Multi_client_update_times[idx] < 0) || timestamp_elapsed_safe(Multi_client_update_times[idx], 1000)){
1539                                         
1540                                         send_client_update_packet(&Net_players[idx]);
1541                                         
1542                                         Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1543                                 }
1544                         }                               
1545                 }
1546
1547                 // for any potential ingame joiners
1548                 multi_handle_ingame_joiners();
1549         }       
1550
1551         // do any file xfer details
1552         multi_xfer_do();
1553
1554         // process any player data details (wav files, pilot pics, etc)
1555         multi_data_do();
1556
1557         // get the other net players data
1558         multi_process_incoming();       
1559
1560         // do any voice details
1561         multi_voice_process();
1562
1563         // process any player messaging details
1564         multi_msg_process();
1565
1566         // process any kicked player details
1567         multi_kick_process();
1568
1569         // process any pending endgame details
1570         multi_endgame_process();
1571
1572         // process object update stuff (for clients and server both)
1573         if(MULTIPLAYER_MASTER){
1574                 multi_oo_process();
1575         }
1576
1577         // if on the standalone, do any gui stuff
1578         if(Game_mode & GM_STANDALONE_SERVER){
1579                 std_do_gui_frame();
1580         }
1581 }
1582
1583
1584 // --------------------------------------------------------------------------------
1585 // standalone_main_init()  the standalone equivalent of the main menu
1586 //
1587
1588 extern int sock_inited;
1589 float frame_time = (float)1.0/(float)30.0;
1590
1591 void standalone_main_init()
1592 {
1593    std_debug_set_standalone_state_string("Main Init");   
1594
1595         Game_mode = (GM_STANDALONE_SERVER | GM_MULTIPLAYER);    
1596
1597         // NETLOG
1598         ml_string(NOX("Standalone server initializing"));
1599
1600         // read in config file
1601         // multi_options_read_config();   
1602
1603         // if we failed to startup on our desired protocol, fail        
1604         if((Multi_options_g.protocol == NET_IPX) && !Ipx_active){                                               
1605 #ifndef PLAT_UNIX
1606                 MessageBox((HWND)os_get_window(), XSTR( "You have selected IPX for multiplayer Freespace, but the IPX protocol was not detected on your machine.", 1402), "Error", MB_OK);
1607 #else
1608                 fprintf (stderr, "ERROR: You have selected IPX for multiplayer Freespace, but the IPX protocol was not detected on your machine.\n");
1609 #endif
1610                 exit(1);
1611         } 
1612         if((Multi_options_g.protocol == NET_TCP) && !Tcp_active){               
1613 #ifndef PLAT_UNIX
1614                 MessageBox((HWND)os_get_window(), XSTR("You have selected TCP/IP for multiplayer Freespace, but the TCP/IP protocol was not detected on your machine.", 362), "Error", MB_OK);
1615 #else
1616                 fprintf (stderr, "ERROR: You have selected TCP/IP for multiplayer Freespace, but the TCP/IP protocol was not detected on your machine.\n");
1617 #endif
1618                 exit(1);
1619         }
1620         
1621         // set the protocol
1622 #ifdef MULTIPLAYER_BETA_BUILD
1623         Multi_options_g.protocol = NET_TCP;
1624         psnet_use_protocol(Multi_options_g.protocol);   
1625
1626         ADDRESS_LENGTH = IP_ADDRESS_LENGTH;             
1627         PORT_LENGTH = IP_PORT_LENGTH;                   
1628 #else
1629         psnet_use_protocol(Multi_options_g.protocol);
1630         switch (Multi_options_g.protocol) {
1631         case NET_IPX:
1632                 ADDRESS_LENGTH = IPX_ADDRESS_LENGTH;
1633                 PORT_LENGTH = IPX_PORT_LENGTH;
1634                 break;
1635
1636         case NET_TCP:
1637                 ADDRESS_LENGTH = IP_ADDRESS_LENGTH;             
1638                 PORT_LENGTH = IP_PORT_LENGTH;                   
1639                 break;
1640
1641         default:
1642                 Int3();
1643         } // end switch
1644 #endif
1645
1646         HEADER_LENGTH = 1;              
1647         
1648         // clear out the Netgame structure and start filling in the values
1649         // NOTE : these values are not incredibly important since they will be overwritten by the host when he joins
1650         memset( &Netgame, 0, sizeof(Netgame) ); 
1651         Netgame.game_state = NETGAME_STATE_FORMING;             // game is currently starting up
1652         Netgame.security = 0;
1653         Netgame.server_addr = Psnet_my_addr;
1654
1655         memset(&The_mission,0,sizeof(The_mission));
1656                 
1657         // reinitialize all systems     
1658         multi_level_init();     
1659
1660         // intialize endgame stuff
1661         multi_endgame_init();
1662
1663         // clear the file xfer system
1664         multi_xfer_reset();
1665         multi_xfer_force_dir(CF_TYPE_MULTI_CACHE);
1666
1667         // reset timer
1668         timestamp_reset();
1669
1670         // setup the netplayer for the standalone
1671         Net_player = &Net_players[0];   
1672         Net_player->tracker_player_id = -1;
1673         Net_player->flags |= (NETINFO_FLAG_AM_MASTER | NETINFO_FLAG_CONNECTED | NETINFO_FLAG_DO_NETWORKING | NETINFO_FLAG_MISSION_OK);
1674         Net_player->state = NETPLAYER_STATE_WAITING;
1675         Net_player->player = Player;
1676         strcpy(Player->callsign, "server");
1677         Net_player->p_info.addr = Psnet_my_addr;
1678         Net_player->s_info.xfer_handle = -1;    
1679         Net_player->player_id = multi_get_new_id();     
1680         Netgame.server = Net_player; 
1681
1682         // maybe flag the game as having a hacked ships.tbl
1683         if(!Game_ships_tbl_valid){
1684                 Netgame.flags |= NG_FLAG_HACKED_SHIPS_TBL;
1685         }
1686         // maybe flag the game as having a hacked weapons.tbl
1687         if(!Game_weapons_tbl_valid){
1688                 Netgame.flags |= NG_FLAG_HACKED_WEAPONS_TBL;
1689         }
1690
1691         // hacked data
1692         if(game_hacked_data()){
1693                 Net_player->flags |= NETINFO_FLAG_HAXOR;
1694         }
1695
1696         // setup debug flags
1697         Netgame.debug_flags = 0;
1698         /*
1699         if(!Cmdline_server_firing){
1700                 Netgame.debug_flags |= NETD_FLAG_CLIENT_FIRING;
1701         }
1702         if(!Cmdline_client_dodamage){
1703                 Netgame.debug_flags |= NETD_FLAG_CLIENT_NODAMAGE;
1704         }
1705         */
1706
1707         // setup the default game name for the standalone
1708         std_connect_set_gamename(NULL);
1709
1710         // set netgame default options
1711         multi_options_set_netgame_defaults(&Netgame.options);
1712
1713         // set local netplayer default options
1714         multi_options_set_local_defaults(&Net_player->p_info.options);
1715
1716         // set our object update level from the standalone default      
1717         Net_player->p_info.options.obj_update_level = Multi_options_g.std_datarate;
1718         switch(Net_player->p_info.options.obj_update_level){
1719         case OBJ_UPDATE_LOW:
1720                 nprintf(("Network","STANDALONE USING LOW UPDATES\n"));
1721                 break;
1722         case OBJ_UPDATE_MEDIUM:
1723                 nprintf(("Network","STANDALONE USING MEDIUM UPDATES\n"));
1724                 break;
1725         case OBJ_UPDATE_HIGH:
1726                 nprintf(("Network","STANDALONE USING HIGH UPDATE\n"));
1727                 break;
1728         case OBJ_UPDATE_LAN:
1729                 nprintf(("Network","STANDALONE USING LAN UPDATE\n"));
1730                 break;
1731         }
1732         
1733         // clear out various things
1734         psnet_flush();
1735         game_flush();
1736         ship_init();
1737
1738         std_debug_set_standalone_state_string("Main Do");
1739         std_set_standalone_fps((float)0);
1740         std_multi_set_standalone_missiontime((float)0);
1741
1742         // load my missions and campaigns
1743         multi_create_list_load_missions();
1744         multi_create_list_load_campaigns();
1745
1746         // if this is a tracker game, validate missions
1747         if(MULTI_IS_TRACKER_GAME){
1748                 multi_update_valid_missions();
1749         }
1750 }
1751
1752
1753 // --------------------------------------------------------------------------------
1754 // standalone_main_do()
1755 //
1756
1757 // DESCRIPTION : the standalone server will wait in this state until the host of the game 
1758 //               is "Waiting". That is, his state==NETPLAYER_STATE_WAITING, and he has finished
1759 //               doing everything and wants to play the game. Once this happens, we will jump
1760 //               into GS_STATE_MULTI_SERVER_WAIT
1761
1762 void standalone_main_do()
1763 {
1764    Sleep(10);  // since nothing will really be going on here, we can afford to give some time
1765                // back to the operating system.
1766
1767         // kind of a do-nothing spin state.
1768         // The standalone will eventually move into the GS_STATE_MULTI_MISSION_SYNC state when a host connects and
1769         // attempts to start a game
1770 }
1771
1772 // --------------------------------------------------------------------------------
1773 // standalone_main_close()
1774 //
1775
1776 void standalone_main_close()
1777 {
1778    std_debug_set_standalone_state_string("Main Close"); 
1779 }
1780
1781 void multi_standalone_reset_all()
1782 {       
1783         int idx;
1784
1785         // NETLOG
1786         ml_string(NOX("Standalone resetting"));
1787         
1788         // shut all game stuff down
1789         game_level_close();
1790
1791         // reinitialize the gui
1792         std_reset_standalone_gui();     
1793
1794         // close down all sockets
1795         for(idx=0;idx<MAX_PLAYERS;idx++){
1796
1797                 // 6/25/98 -- MWA -- call delete_player here to remove the player.  This closes down the socket
1798                 // and marks the player as not connected anymore.  It is probably cleaner to do this.
1799                 if ( &Net_players[idx] != Net_player ) {
1800                         delete_player( idx );
1801                 }               
1802         }
1803                 
1804         // make sure we go to the proper state. 
1805         if(gameseq_get_state() == GS_STATE_STANDALONE_MAIN){
1806                 standalone_main_init();
1807         }
1808         gameseq_post_event(GS_EVENT_STANDALONE_MAIN);   
1809 }
1810
1811 // --------------------------------------------------------------------------------
1812 // multi_server_wait_init()  do stuff like setting the status bits correctly
1813 //
1814
1815 void multi_standalone_wait_init()
1816 {       
1817         std_debug_set_standalone_state_string("Wait Do");
1818         std_multi_add_goals();   // fill in the goals for the mission into the tree view
1819         multi_reset_timestamps();
1820
1821         // create the bogus standalone object
1822         multi_create_standalone_object();
1823 }
1824
1825
1826 // --------------------------------------------------------------------------------
1827 // multi_server_wait_do_frame() wait for everyone to log in or the host to send commands
1828 // 
1829
1830 // DESCRIPTION : we will be in this state once the host of the game is waiting for everyone
1831 //               to be finished and ready to go, at which point, we will will tell everyone
1832 //               to enter the game, and we will start simulating ourselves. Note that most of
1833 //               this code is lifted from multi_wait_do_frame()
1834 void multi_standalone_wait_do()
1835 {
1836 }
1837
1838 // --------------------------------------------------------------------------------
1839 // multi_server_wait_close() cleanup
1840 //
1841
1842 void multi_standalone_wait_close()
1843 {
1844         std_debug_set_standalone_state_string("Wait Close / Game Play");
1845         
1846         // all players should reset sequencing
1847         int idx;
1848         for(idx=0;idx<MAX_PLAYERS;idx++){
1849                 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
1850                         Net_players[idx].client_cinfo_seq = 0;
1851                         Net_players[idx].client_server_seq = 0; 
1852                 }
1853         }
1854 }
1855
1856
1857 // this is an artificial state which will push the standalone into the main state without it having to go through 
1858 // the init function (which would disconnect everyone and generally just screw things up)
1859 // it will also eventually do tracker stats update
1860 extern int Multi_debrief_server_framecount;
1861 void multi_standalone_postgame_init()   
1862 {
1863         std_debug_set_standalone_state_string("Postgame / Send Stats");
1864
1865         // NETLOG
1866         ml_string(NOX("Standlone entering postgame"));
1867
1868         mission_goal_fail_incomplete();
1869
1870         // handle campaign stuff
1871         if ( Game_mode & GM_CAMPAIGN_MODE ) {
1872                 // MUST store goals and events first - may be used to evaluate next mission
1873                 // store goals and events
1874                 mission_campaign_store_goals_and_events();
1875
1876                 // evaluate next mission
1877                 mission_campaign_eval_next_mission();
1878         }       
1879
1880         // always set my state to be "DEBRIEF_ACCEPT"
1881         Net_player->state = NETPLAYER_STATE_DEBRIEF_ACCEPT;     
1882
1883         // mark stats as not being store yet
1884         Netgame.flags &= ~(NG_FLAG_STORED_MT_STATS);
1885
1886         Multi_debrief_server_framecount = 0;
1887
1888         // reset network timestamps
1889         multi_reset_timestamps();
1890 }
1891
1892 void multi_standalone_postgame_do()
1893 {
1894         // wait until everyone is in the debriefing
1895         if((Netgame.game_state != NETGAME_STATE_DEBRIEF) && multi_netplayer_state_check(NETPLAYER_STATE_DEBRIEF, 1)){           
1896                 Netgame.game_state = NETGAME_STATE_DEBRIEF;
1897                 send_netgame_update_packet();
1898                 debrief_multi_server_stuff();
1899         }
1900         
1901         // process server debriefing details
1902         if(Netgame.game_state == NETGAME_STATE_DEBRIEF){
1903                 multi_debrief_server_process();
1904         }
1905 }
1906
1907 void multi_standalone_postgame_close()
1908 {
1909 }
1910
1911 void multi_reset_timestamps()
1912 {
1913         int i;
1914
1915         for ( i = 0 ; i < MAX_PLAYERS; i++ ){
1916                 Multi_client_update_times[i] = -1;
1917         }
1918         Netgame_send_time = -1;
1919         Gameinfo_send_time = -1;        
1920         Next_ping_time = -1;
1921         State_send_time = -1;
1922         Next_bytes_time = -1;
1923
1924         chatbox_reset_timestamps();
1925
1926         // do for all players so that ingame joiners work properly.
1927         for (i = 0; i < MAX_PLAYERS; i++ ) {
1928                 Players[i].update_dumbfire_time = timestamp(0);
1929                 Players[i].update_lock_time = timestamp(0);
1930
1931                 Net_players[i].s_info.voice_token_timestamp = -1;
1932         }
1933
1934         // reset standalone gui timestamps (these are not game critical, so there is not much danger)
1935         std_reset_timestamps();
1936
1937         // initialize all object update timestamps
1938         multi_oo_gameplay_init();
1939 }
1940
1941 // netgame debug flags for debug console stuff
1942 DCF(netd, "change/list netgame debug flags")
1943 {
1944         dc_get_arg(ARG_INT);
1945         
1946         // if we got an integer, and we're the server, change flags
1947         if((Dc_arg_type & ARG_INT) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Dc_arg_int <= 7)){
1948                 Netgame.debug_flags ^= (1<<Dc_arg_int);
1949         }
1950
1951         // display network flags
1952         dc_printf("BITS\n");
1953         // dc_printf("1 - Client side firing (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING ? 1 : 0);
1954         // dc_printf("2 - Client nodamage (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE ? 1 : 0);
1955 }
1956
1957 // display any multiplayer/networking information here
1958 void multi_display_netinfo()
1959 {
1960         int sx = gr_screen.max_w - 200;
1961         int sy = 20;
1962         int idx;
1963
1964         // not multiplayer
1965         if(!(Game_mode & GM_MULTIPLAYER)){
1966                 return;
1967         }
1968
1969         gr_set_color_fast(&Color_normal);
1970
1971         // server or client
1972         if(MULTIPLAYER_MASTER){
1973                 gr_string(sx, sy, "SERVER"); sy += 10;
1974
1975                 for(idx=0; idx<MAX_PLAYERS; idx++){
1976                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx]) && (Net_players[idx].player != NULL)){
1977                                 if(Net_players[idx].sv_last_pl < 0){
1978                                         gr_printf(sx, sy, "%s : %d, %d pl", Net_players[idx].player->callsign, Net_players[idx].sv_bytes_sent, 0); sy += 10;
1979                                 } else {
1980                                         gr_printf(sx, sy, "%s : %d, %d pl", Net_players[idx].player->callsign, Net_players[idx].sv_bytes_sent, Net_players[idx].sv_last_pl); sy += 10;
1981                                 }
1982                         }
1983                 }
1984         } else {
1985                 gr_string(sx, sy, "CLIENT"); sy += 10;
1986
1987                 // display PL
1988                 if(Net_player != NULL){
1989                         if(Net_player->cl_last_pl < 0){
1990                                 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, 0); sy += 10;
1991                         } else {
1992                                 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, Net_player->cl_last_pl); sy += 10;
1993                         }
1994                 }
1995         }
1996 }