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