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