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