]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_options.cpp
Freespace 1 support
[taylor/freespace2.git] / src / network / multi_options.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_options.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.4  2003/05/25 02:30:43  taylor
17  * Freespace 1 support
18  *
19  * Revision 1.3  2002/06/09 04:41:23  relnev
20  * added copyright header
21  *
22  * Revision 1.2  2002/05/26 20:22:48  theoddone33
23  * Most of network/ works
24  *
25  * Revision 1.1.1.1  2002/05/03 03:28:10  root
26  * Initial import.
27  * 
28  * 
29  * 22    8/27/99 12:32a Dave
30  * Allow the user to specify a local port through the launcher.
31  * 
32  * 21    8/22/99 1:19p Dave
33  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
34  * which d3d cards are detected.
35  * 
36  * 20    8/04/99 6:01p Dave
37  * Oops. Make sure standalones log in.
38  * 
39  * 19    7/09/99 9:51a Dave
40  * Added thick polyline code.
41  * 
42  * 18    5/03/99 8:32p Dave
43  * New version of multi host options screen.
44  * 
45  * 17    4/25/99 7:43p Dave
46  * Misc small bug fixes. Made sun draw properly.
47  * 
48  * 16    4/20/99 6:39p Dave
49  * Almost done with artillery targeting. Added support for downloading
50  * images on the PXO screen.
51  * 
52  * 15    3/10/99 6:50p Dave
53  * Changed the way we buffer packets for all clients. Optimized turret
54  * fired packets. Did some weapon firing optimizations.
55  * 
56  * 14    3/09/99 6:24p Dave
57  * More work on object update revamping. Identified several sources of
58  * unnecessary bandwidth.
59  * 
60  * 13    3/08/99 7:03p Dave
61  * First run of new object update system. Looks very promising.
62  * 
63  * 12    2/21/99 6:01p Dave
64  * Fixed standalone WSS packets. 
65  * 
66  * 11    2/19/99 2:55p Dave
67  * Temporary checking to report the winner of a squad war match.
68  * 
69  * 10    2/12/99 6:16p Dave
70  * Pre-mission Squad War code is 95% done.
71  * 
72  * 9     2/11/99 3:08p Dave
73  * PXO refresh button. Very preliminary squad war support.
74  * 
75  * 8     11/20/98 11:16a Dave
76  * Fixed up IPX support a bit. Making sure that switching modes and
77  * loading/saving pilot files maintains proper state.
78  * 
79  * 7     11/19/98 4:19p Dave
80  * Put IPX sockets back in psnet. Consolidated all multiplayer config
81  * files into one.
82  * 
83  * 6     11/19/98 8:03a Dave
84  * Full support for D3-style reliable sockets. Revamped packet lag/loss
85  * system, made it receiver side and at the lowest possible level.
86  * 
87  * 5     11/17/98 11:12a Dave
88  * Removed player identification by address. Now assign explicit id #'s.
89  * 
90  * 4     10/13/98 9:29a Dave
91  * Started neatening up freespace.h. Many variables renamed and
92  * reorganized. Added AlphaColors.[h,cpp]
93  * 
94  * 3     10/07/98 6:27p Dave
95  * Globalized mission and campaign file extensions. Removed Silent Threat
96  * special code. Moved \cache \players and \multidata into the \data
97  * directory.
98  * 
99  * 2     10/07/98 10:53a Dave
100  * Initial checkin.
101  * 
102  * 1     10/07/98 10:50a Dave
103  * 
104  * 20    9/10/98 1:17p Dave
105  * Put in code to flag missions and campaigns as being MD or not in Fred
106  * and Freespace. Put in multiplayer support for filtering out MD
107  * missions. Put in multiplayer popups for warning of non-valid missions.
108  * 
109  * 19    7/07/98 2:49p Dave
110  * UI bug fixes.
111  * 
112  * 18    6/04/98 11:04a Allender
113  * object update level stuff.  Don't reset to high when becoming an
114  * observer of any type.  default to low when guy is a dialup customer
115  * 
116  * 17    5/24/98 3:45a Dave
117  * Minor object update fixes. Justify channel information on PXO. Add a
118  * bunch of configuration stuff for the standalone.
119  * 
120  * 16    5/19/98 1:35a Dave
121  * Tweaked pxo interface. Added rankings url to pxo.cfg. Make netplayer
122  * local options update dynamically in netgames.
123  * 
124  * 15    5/08/98 5:05p Dave
125  * Go to the join game screen when quitting multiplayer. Fixed mission
126  * text chat bugs. Put mission type symbols on the create game list.
127  * Started updating standalone gui controls.
128  * 
129  * 14    5/06/98 12:36p Dave
130  * Make sure clients can leave the debrief screen easily at all times. Fix
131  * respawn count problem.
132  * 
133  * 13    5/03/98 7:04p Dave
134  * Make team vs. team work mores smoothly with standalone. Change how host
135  * interacts with standalone for picking missions. Put in a time limit for
136  * ingame join ship select. Fix ingame join ship select screen for Vasudan
137  * ship icons.
138  * 
139  * 12    5/03/98 2:52p Dave
140  * Removed multiplayer furball mode.
141  * 
142  * 11    4/23/98 6:18p Dave
143  * Store ETS values between respawns. Put kick feature in the text
144  * messaging system. Fixed text messaging system so that it doesn't
145  * process or trigger ship controls. Other UI fixes.
146  * 
147  * 10    4/22/98 5:53p Dave
148  * Large reworking of endgame sequencing. Updated multi host options
149  * screen for new artwork. Put in checks for host or team captains leaving
150  * midgame.
151  * 
152  * 9     4/16/98 11:39p Dave
153  * Put in first run of new multiplayer options screen. Still need to
154  * complete final tab.
155  * 
156  * 8     4/13/98 4:50p Dave
157  * Maintain status of weapon bank/links through respawns. Put # players on
158  * create game mission list. Make observer not have engine sounds. Make
159  * oberver pivot point correct. Fixed respawn value getting reset every
160  * time host options screen started.
161  * 
162  * 7     4/09/98 11:01p Dave
163  * Put in new multi host options screen. Tweaked multiplayer options a
164  * bit.
165  * 
166  * 6     4/09/98 5:43p Dave
167  * Remove all command line processing from the demo. Began work fixing up
168  * the new multi host options screen.
169  * 
170  * 5     4/06/98 6:37p Dave
171  * Put in max_observers netgame server option. Make sure host is always
172  * defaulted to alpha 1 or zeta 1. Changed create game so that MAX_PLAYERS
173  * can always join but need to be kicked before commit can happen. Put in
174  * support for server ending a game and notifying clients of a special
175  * condition.
176  * 
177  * 4     4/04/98 4:22p Dave
178  * First rev of UDP reliable sockets is done. Seems to work well if not
179  * overly burdened.
180  * 
181  * 3     4/03/98 1:03a Dave
182  * First pass at unreliable guaranteed delivery packets.
183  * 
184  * 2     3/31/98 4:51p Dave
185  * Removed medals screen and multiplayer buttons from demo version. Put in
186  * new pilot popup screen. Make ships in mp team vs. team have proper team
187  * ids. Make mp respawns a permanent option saved in the player file.
188  * 
189  * 1     3/30/98 6:24p Dave
190  *  
191  * 
192  * $NoKeywords: $
193  */
194
195 #ifndef PLAT_UNIX
196 #include <windows.h>
197 #endif
198 #include "cmdline.h"
199 #include "osregistry.h"
200 #include "multi.h"
201 #include "multimsgs.h"
202 #include "freespace.h"
203 #include "stand_gui.h"
204 #include "multiutil.h"
205 #include "multi_voice.h"
206 #include "multi_options.h"
207 #include "multi_team.h"
208
209 // ----------------------------------------------------------------------------------
210 // MULTI OPTIONS DEFINES/VARS
211 //
212
213 // packet codes
214 #define MULTI_OPTION_SERVER                                             0                               // server update follows
215 #define MULTI_OPTION_LOCAL                                                      1                               // local netplayer options follow
216 #define MULTI_OPTION_START_GAME                                 2                               // host's start game options on the standalone server
217 #define MULTI_OPTION_MISSION                                            3                               // host's mission selection stuff on a standalone server
218
219 // global options
220 #define MULTI_CFG_FILE                                                          NOX("multi.cfg")
221 multi_global_options Multi_options_g;
222
223 char Multi_options_proxy[512] = "";
224 ushort Multi_options_proxy_port = 0;
225
226 // ----------------------------------------------------------------------------------
227 // MULTI OPTIONS FUNCTIONS
228 //
229
230 // load in the config file
231 #define NEXT_TOKEN()                                            do { tok = strtok(NULL, "\n"); if(tok != NULL){ drop_leading_white_space(tok); drop_trailing_white_space(tok); } } while(0);
232 #define SETTING(s)                                              ( !stricmp(tok, s) )
233 void multi_options_read_config()
234 {
235         CFILE *in;
236         char str[512];
237         char *tok = NULL;
238
239         // set default value for the global multi options
240         memset(&Multi_options_g, 0, sizeof(multi_global_options));
241         Multi_options_g.protocol = NET_TCP;     
242
243         // do we have a forced port via commandline or registry?
244         ushort forced_port = (ushort)os_config_read_uint(NULL, "ForcePort", 0); 
245         Multi_options_g.port = (Cmdline_network_port >= 0) ? (ushort)Cmdline_network_port : forced_port == 0 ? (ushort)DEFAULT_GAME_PORT : forced_port;
246
247         Multi_options_g.log = (Cmdline_multi_log) ? 1 : 0;
248         Multi_options_g.datarate_cap = OO_HIGH_RATE_DEFAULT;
249         strcpy(Multi_options_g.user_tracker_ip, "");    
250         strcpy(Multi_options_g.game_tracker_ip, "");    
251         strcpy(Multi_options_g.pxo_ip, "");     
252         strcpy(Multi_options_g.pxo_rank_url, "");       
253         strcpy(Multi_options_g.pxo_create_url, "");     
254         strcpy(Multi_options_g.pxo_verify_url, "");     
255         strcpy(Multi_options_g.pxo_banner_url, "");
256
257         // standalone values
258         Multi_options_g.std_max_players = -1;
259         Multi_options_g.std_datarate = OBJ_UPDATE_HIGH;
260         Multi_options_g.std_voice = 1;
261         memset(Multi_options_g.std_passwd, 0, STD_PASSWD_LEN);
262         memset(Multi_options_g.std_pname, 0, STD_NAME_LEN);
263         Multi_options_g.std_framecap = 30;
264         
265         // read in the config file
266         in = cfopen(MULTI_CFG_FILE, "rt", CFILE_NORMAL, CF_TYPE_DATA);
267         
268         // if we failed to open the config file, user default settings
269         if(in == NULL){
270                 nprintf(("Network","Failed to open network config file, using default settings\n"));            
271                 return;
272         }
273
274         while(!cfeof(in)){
275                 // read in the game info
276                 memset(str,0,512);
277                 cfgets(str,512,in);
278
279                 // parse the first line
280                 tok = strtok(str," \t");
281
282                 // check the token
283                 if(tok != NULL){
284                         drop_leading_white_space(tok);
285                         drop_trailing_white_space(tok);                 
286                 } else {
287                         continue;
288                 }               
289
290                 // all possible options
291                 // only standalone cares about the following options
292                 if(Is_standalone){
293                         if(SETTING("+pxo")){                    
294                                 // setup PXO mode
295                                 NEXT_TOKEN();
296                                 if(tok != NULL){
297                                         // whee!
298                                 }
299                         } else 
300                         if(SETTING("+name")){
301                                 // set the standalone server's permanent name
302                                 NEXT_TOKEN();
303                                 if(tok != NULL){
304                                         strncpy(Multi_options_g.std_pname, tok, STD_NAME_LEN);
305                                 }
306                         } else 
307                         if(SETTING("+no_voice")){
308                                 // standalone won't allow voice transmission
309                                 Multi_options_g.std_voice = 0;
310                         } else
311                         if(SETTING("+max_players")){
312                                 // set the max # of players on the standalone
313                                 NEXT_TOKEN();
314                                 if(tok != NULL){
315                                         if(!((atoi(tok) < 1) || (atoi(tok) > MAX_PLAYERS))){
316                                                 Multi_options_g.std_max_players = atoi(tok);
317                                         }
318                                 }
319                         } else 
320                         if(SETTING("+ban")){
321                                 // ban a player
322                                 NEXT_TOKEN();
323                                 if(tok != NULL){
324                                         std_add_ban(tok);
325                                 }
326                         } else 
327                         if(SETTING("+passwd")){
328                                 // set the standalone host password
329                                 NEXT_TOKEN();
330                                 if(tok != NULL){
331                                         strncpy(Multi_options_g.std_passwd, tok, STD_PASSWD_LEN);
332
333                                         // yuck
334 #ifdef PLAT_UNIX
335                                         STUB_FUNCTION;
336 #else
337                                         extern HWND Multi_std_host_passwd;
338                                         SetWindowText(Multi_std_host_passwd, Multi_options_g.std_passwd);
339 #endif
340                                 }
341                         } else 
342                         if(SETTING("+low_update")){
343                                 // set standalone to low updates
344                                 Multi_options_g.std_datarate = OBJ_UPDATE_LOW;
345                         } else
346                         if(SETTING("+med_update")){
347                                 // set standalone to medium updates
348                                 Multi_options_g.std_datarate = OBJ_UPDATE_MEDIUM;
349                         } else 
350                         if(SETTING("+high_update")){
351                                 // set standalone to high updates
352                                 Multi_options_g.std_datarate = OBJ_UPDATE_HIGH;
353                         } else 
354                         if(SETTING("+lan_update")){
355                                 // set standalone to high updates
356                                 Multi_options_g.std_datarate = OBJ_UPDATE_LAN;
357                         } 
358                 }
359
360                 // common to all modes
361                 if(SETTING("+user_server")){
362                         // ip addr of user tracker
363                         NEXT_TOKEN();
364                         if(tok != NULL){
365                                 strcpy(Multi_options_g.user_tracker_ip, tok);
366                         }
367                 } else
368                 if(SETTING("+game_server")){
369                         // ip addr of game tracker
370                         NEXT_TOKEN();
371                         if(tok != NULL){
372                                 strcpy(Multi_options_g.game_tracker_ip, tok);
373                         }
374                 } else
375                 if(SETTING("+chat_server")){
376                         // ip addr of pxo chat server
377                         NEXT_TOKEN();
378                         if(tok != NULL){
379                                 strcpy(Multi_options_g.pxo_ip, tok);
380                         }
381                 } else
382                 if(SETTING("+rank_url")){
383                         // url of pilot rankings page
384                         NEXT_TOKEN();
385                         if(tok != NULL){
386                                 strcpy(Multi_options_g.pxo_rank_url, tok);
387                         }
388                 } else
389                 if(SETTING("+create_url")){
390                         // url of pxo account create page
391                         NEXT_TOKEN();
392                         if(tok != NULL){
393                                 strcpy(Multi_options_g.pxo_create_url, tok);
394                         }
395                 } else
396                 if(SETTING("+verify_url")){
397                         // url of pxo account verify page
398                         NEXT_TOKEN();
399                         if(tok != NULL){
400                                 strcpy(Multi_options_g.pxo_verify_url, tok);
401                         }
402                 } else
403                 if(SETTING("+banner_url")){
404                         // url of pxo account verify page
405                         NEXT_TOKEN();
406                         if(tok != NULL){
407                                 strcpy(Multi_options_g.pxo_banner_url, tok);
408                         }
409                 } else
410                 if(SETTING("+datarate")){
411                         // set the max datarate for high updates
412                         NEXT_TOKEN();
413                         if(tok != NULL){
414                                 if(atoi(tok) >= 4000){
415                                         Multi_options_g.datarate_cap = atoi(tok);
416                                 }
417                         }                       
418                 }
419                 if(SETTING("+http_proxy")){
420                         // get the proxy server
421                         NEXT_TOKEN();
422                         if(tok != NULL){                                
423                                 char *ip = strtok(tok, ":");
424                                 if(ip != NULL){
425                                         strcpy(Multi_options_proxy, ip);
426                                 }
427                                 ip = strtok(NULL, "");
428                                 if(ip != NULL){
429                                         Multi_options_proxy_port = (ushort)atoi(ip);
430                                 } else {
431                                         strcpy(Multi_options_proxy, "");
432                                 }
433                         }
434                 }
435         }
436
437         // close the config file
438         cfclose(in);
439         in = NULL;
440 }
441
442 // set netgame defaults 
443 // NOTE : should be used when creating a newpilot
444 void multi_options_set_netgame_defaults(multi_server_options *options)
445 {
446         // any player can do squadmate messaging
447         options->squad_set = MSO_SQUAD_ANY;
448
449         // only the host can end the game
450         options->endgame_set = MSO_END_HOST;
451
452         // allow ingame file xfer and custom pilot pix
453         options->flags = (MSO_FLAG_INGAME_XFER | MSO_FLAG_ACCEPT_PIX);
454
455         // set the default time limit to be -1 (no limit)
456         options->mission_time_limit = fl2f(-1.0f);
457
458         // set the default max kills for a mission
459         options->kill_limit = 9999;
460
461         // set the default # of respawns
462         options->respawn = 2;
463
464         // set the default # of max observers
465         options->max_observers = 2;
466
467         // set the default netgame qos
468         options->voice_qos = 10;
469
470         // set the default token timeout
471         options->voice_token_wait = 2000;                               // he must wait 2 seconds between voice gets
472
473         // set the default max voice record time
474         options->voice_record_time = 5000;
475 }
476
477 // set local netplayer defaults
478 // NOTE : should be used when creating a newpilot
479 void multi_options_set_local_defaults(multi_local_options *options)
480 {
481         // accept pix by default and broadcast on the local subnet
482         options->flags = (MLO_FLAG_ACCEPT_PIX | MLO_FLAG_LOCAL_BROADCAST);      
483
484         // set the object update level based on the type of network connection specified by the user
485         // at install (or launcher) time.
486         if ( Psnet_connection == NETWORK_CONNECTION_DIALUP ) {
487                 options->obj_update_level = OBJ_UPDATE_LOW;
488         } else {
489                 options->obj_update_level = OBJ_UPDATE_HIGH;
490         }
491 }
492
493 // fill in the passed netgame options struct with the data from my player file data (only host/server should do this)
494 void multi_options_netgame_load(multi_server_options *options)
495 {
496         if(options != NULL){
497                 memcpy(options,&Player->m_server_options,sizeof(multi_server_options));
498         }       
499 }
500
501 // fill in the passed local options struct with the data from my player file data (all machines except standalone should do this)
502 void multi_options_local_load(multi_local_options *options, net_player *pxo_pl)
503 {
504         if(options != NULL){
505                 memcpy(options,&Player->m_local_options,sizeof(multi_local_options));
506         }
507
508         // stuff pxo squad info
509 #ifndef MAKE_FS1
510         if(pxo_pl != NULL){
511                 strcpy(pxo_pl->p_info.pxo_squad_name, Multi_tracker_squad_name);                
512         }
513 #endif
514 }
515
516 // update everyone on the current netgame options
517 void multi_options_update_netgame()
518 {
519         ubyte data[MAX_PACKET_SIZE],code;
520         int packet_size = 0;
521         
522         Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
523
524         // build the header and add the opcode
525         BUILD_HEADER(OPTIONS_UPDATE);
526         code = MULTI_OPTION_SERVER;
527         ADD_DATA(code);
528
529         // add the netgame options
530         ADD_DATA(Netgame.options);
531
532         // send the packet
533         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
534                 multi_io_send_to_all_reliable(data, packet_size);
535         } else {
536                 multi_io_send_reliable(Net_player, data, packet_size);
537         }
538 }
539
540 // update everyone with my local settings
541 void multi_options_update_local()
542 {
543         ubyte data[MAX_PACKET_SIZE],code;
544         int packet_size = 0;
545         
546         // if i'm the server, don't do anything
547         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
548                 return;
549         }
550
551         // build the header and add the opcode
552         BUILD_HEADER(OPTIONS_UPDATE);
553         code = MULTI_OPTION_LOCAL;
554         ADD_DATA(code);
555
556         // add the netgame options
557         ADD_DATA(Net_player->p_info.options);
558
559         // send the packet              
560         multi_io_send_reliable(Net_player, data, packet_size);
561 }
562
563 // update the standalone with the settings I have picked at the "start game" screen
564 void multi_options_update_start_game(netgame_info *ng)
565 {
566         ubyte data[MAX_PACKET_SIZE],code;
567         int packet_size = 0;
568
569         // should be a host on a standalone
570         Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
571
572         // build the header
573         BUILD_HEADER(OPTIONS_UPDATE);
574         code = MULTI_OPTION_START_GAME;
575         ADD_DATA(code);
576
577         // add the start game options
578         ADD_STRING(ng->name);
579         ADD_DATA(ng->mode);
580         ADD_DATA(ng->security);
581
582         // add mode-specific data
583         switch(ng->mode){
584         case NG_MODE_PASSWORD:
585                 ADD_STRING(ng->passwd);
586                 break;
587         case NG_MODE_RANK_ABOVE:
588         case NG_MODE_RANK_BELOW:
589                 ADD_DATA(ng->rank_base);
590                 break;
591         }
592
593         // send to the standalone server        
594         multi_io_send_reliable(Net_player, data, packet_size);
595 }
596
597 // update the standalone with the mission settings I have picked (mission filename, etc)
598 void multi_options_update_mission(netgame_info *ng, int campaign_mode)
599 {
600         ubyte data[MAX_PACKET_SIZE],code;
601         int packet_size = 0;
602
603         // should be a host on a standalone
604         Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
605
606         // build the header
607         BUILD_HEADER(OPTIONS_UPDATE);
608         code = MULTI_OPTION_MISSION;
609         ADD_DATA(code);
610
611         // type (coop or team vs. team)
612         ADD_DATA(ng->type_flags);
613
614         // respawns
615         ADD_DATA(ng->respawn);
616
617         // add the mission/campaign filename
618         code = (ubyte)campaign_mode;
619         ADD_DATA(code);
620         if(campaign_mode){
621                 ADD_STRING(ng->campaign_name);
622         } else {
623                 ADD_STRING(ng->mission_name);
624         }
625
626         // send to the server   
627         multi_io_send_reliable(Net_player, data, packet_size);
628 }
629
630
631 // ----------------------------------------------------------------------------------
632 // MULTI OPTIONS FUNCTIONS
633 //
634
635 // process an incoming multi options packet
636 void multi_options_process_packet(unsigned char *data, header *hinfo)
637 {
638         ubyte code;     
639         multi_local_options bogus;
640         int idx,player_index;
641         char str[255];
642         int offset = HEADER_LENGTH;
643
644         // find out who is sending this data    
645         player_index = find_player_id(hinfo->id);
646
647         // get the packet code
648         GET_DATA(code);
649         switch(code){
650         // get the start game options
651         case MULTI_OPTION_START_GAME:
652                 Assert(Game_mode & GM_STANDALONE_SERVER);
653
654                 // get the netgame name
655                 GET_STRING(Netgame.name);               
656
657                 // get the netgame mode
658                 GET_DATA(Netgame.mode);
659
660                 // get the security #
661                 GET_DATA(Netgame.security);
662
663                 // get mode specific data
664                 switch(Netgame.mode){
665                 case NG_MODE_PASSWORD:
666                         GET_STRING(Netgame.passwd);
667                         break;
668                 case NG_MODE_RANK_ABOVE:
669                 case NG_MODE_RANK_BELOW:
670                         GET_DATA(Netgame.rank_base);
671                         break;
672                 }
673
674                 // update standalone stuff
675                 std_connect_set_gamename(Netgame.name);
676                 std_multi_update_netgame_info_controls();
677                 break;
678
679         // get mission choice options
680         case MULTI_OPTION_MISSION:
681                 netgame_info ng;
682                 char title[NAME_LENGTH+1];
683                 int campaign_type,max_players;
684                 
685                 memset(&ng,0,sizeof(netgame_info));
686
687                 Assert(Game_mode & GM_STANDALONE_SERVER);
688
689                 // coop or team vs. team mode
690                 GET_DATA(ng.type_flags);
691                 if((ng.type_flags & NG_TYPE_TEAM) && !(Netgame.type_flags & NG_TYPE_TEAM)){
692                         multi_team_reset();
693                 }
694                 // if squad war was switched on
695                 if((ng.type_flags & NG_TYPE_SW) && !(Netgame.type_flags & NG_TYPE_SW)){
696                         mprintf(("STANDALONE TURNED ON SQUAD WAR!!\n"));
697                 }
698                 Netgame.type_flags = ng.type_flags;
699
700                 // new respawn count
701                 GET_DATA(Netgame.respawn);
702
703                 // name string
704                 memset(str,255,0);
705
706                 GET_DATA(code);
707                 // campaign mode
708                 if(code){
709                         GET_STRING(ng.campaign_name);
710
711                         // set the netgame max players here if the filename has changed
712                         if(strcmp(Netgame.campaign_name,ng.campaign_name)){                             
713                                 memset(title,0,NAME_LENGTH+1);                  
714                                 if(!mission_campaign_get_info(ng.campaign_name,title,&campaign_type,&max_players)){
715                                         Netgame.max_players = 0;
716                                 } else {
717                                         Netgame.max_players = max_players;
718                                 }
719
720                                 strcpy(Netgame.campaign_name,ng.campaign_name);
721                         }
722
723                         Netgame.campaign_mode = 1;
724
725                         // put brackets around the campaign name
726                         if(Game_mode & GM_STANDALONE_SERVER){
727                                 strcpy(str,"(");
728                                 strcat(str,Netgame.campaign_name);
729                                 strcat(str,")");
730                                 std_multi_set_standalone_mission_name(str);
731                         }
732                 }
733                 // non-campaign mode
734                 else {
735                         GET_STRING(ng.mission_name);
736
737                         if(strcmp(Netgame.mission_name,ng.mission_name)){
738                                 if(strlen(ng.mission_name)){
739                                         Netgame.max_players = mission_parse_get_multi_mission_info( ng.mission_name );
740                                 } else {
741                                         // setting this to -1 will prevent us from being seen on the network
742                                         Netgame.max_players = -1;                               
743                                 }
744                                 strcpy(Netgame.mission_name,ng.mission_name);
745                                 strcpy(Game_current_mission_filename,Netgame.mission_name);                             
746                         }                       
747
748                         Netgame.campaign_mode = 0;
749
750                         // set the mission name
751                         if(Game_mode & GM_STANDALONE_SERVER){
752                                 std_multi_set_standalone_mission_name(Netgame.mission_name);                    
753                         }
754                 }
755                 
756                 send_netgame_update_packet();      
757                 break;
758
759         // get the netgame options
760         case MULTI_OPTION_SERVER:               
761                 GET_DATA(Netgame.options);
762
763                 // if we're a standalone set for no sound, do so here
764                 if((Game_mode & GM_STANDALONE_SERVER) && !Multi_options_g.std_voice){
765                         Netgame.options.flags |= MSO_FLAG_NO_VOICE;
766                 } else {
767                         // maybe update the quality of sound
768                         multi_voice_maybe_update_vars(Netgame.options.voice_qos,Netgame.options.voice_record_time);
769                 }
770
771                 // set the skill level
772                 Game_skill_level = Netgame.options.skill_level;         
773
774                 if((Game_mode & GM_STANDALONE_SERVER) && !(Game_mode & GM_CAMPAIGN_MODE)){
775                         Netgame.respawn = Netgame.options.respawn;
776                 }
777
778                 // if we have the "temp closed" flag toggle
779                 if(Netgame.options.flags & MLO_FLAG_TEMP_CLOSED){
780                         Netgame.flags ^= NG_FLAG_TEMP_CLOSED;
781                 }
782                 Netgame.options.flags &= ~(MLO_FLAG_TEMP_CLOSED);
783
784                 // if i'm the standalone server, I should rebroadcast to all other players
785                 if(Game_mode & GM_STANDALONE_SERVER){
786                         for(idx=0;idx<MAX_PLAYERS;idx++){
787                                 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx]) && (&Net_players[idx] != &Net_players[player_index]) ){
788                                         multi_io_send_reliable(&Net_players[idx], data, offset);
789                                 }
790                         }
791
792                         send_netgame_update_packet();
793                 }
794                 break;
795         
796         // local netplayer options
797         case MULTI_OPTION_LOCAL:
798                 if(player_index == -1){
799                         GET_DATA(bogus);
800                 } else {
801                         GET_DATA(Net_players[player_index].p_info.options);
802                 }               
803                 break;
804         }
805         PACKET_SET_SIZE();
806 }
807
808
809
810