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