]> icculus.org git repositories - taylor/freespace2.git/blob - src/menuui/optionsmenumulti.cpp
Freespace 1 support
[taylor/freespace2.git] / src / menuui / optionsmenumulti.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/MenuUI/OptionsMenuMulti.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.6  2003/05/25 02:30:42  taylor
17  * Freespace 1 support
18  *
19  * Revision 1.5  2002/06/09 04:41:22  relnev
20  * added copyright header
21  *
22  * Revision 1.4  2002/06/05 08:05:29  relnev
23  * stub/warning removal.
24  *
25  * reworked the sound code.
26  *
27  * Revision 1.3  2002/06/02 06:02:59  relnev
28  * tcp.cfg namefix
29  *
30  * Revision 1.2  2002/05/07 03:16:46  theoddone33
31  * The Great Newline Fix
32  *
33  * Revision 1.1.1.1  2002/05/03 03:28:09  root
34  * Initial import.
35  *  
36  * 
37  * 21    10/25/99 5:47p Jefff
38  * reassigned some xstr ids
39  * 
40  * 20    8/02/99 2:44p Dave
41  * Disable IPX for demo build.
42  * 
43  * 19    7/15/99 7:15p Jefff
44  * Added various sound FX
45  * 
46  * 18    7/15/99 9:20a Andsager
47  * FS2_DEMO initial checkin
48  * 
49  * 17    6/25/99 11:59a Dave
50  * Multi options screen.
51  * 
52  * 16    6/22/99 7:03p Dave
53  * New detail options screen.
54  * 
55  * 15    4/25/99 3:02p Dave
56  * Build defines for the E3 build.
57  * 
58  * 14    2/25/99 4:19p Dave
59  * Added multiplayer_beta defines. Added cd_check define. Fixed a few
60  * release build warnings. Added more data to the squad war request and
61  * response packets.
62  * 
63  * 13    2/19/99 2:55p Dave
64  * Temporary checking to report the winner of a squad war match.
65  * 
66  * 12    2/17/99 2:10p Dave
67  * First full run of squad war. All freespace and tracker side stuff
68  * works.
69  * 
70  * 11    2/12/99 6:16p Dave
71  * Pre-mission Squad War code is 95% done.
72  * 
73  * 10    2/05/99 7:22p Neilk
74  * Fixed gamma bitmap and converted coordinates for multiple resolutions
75  * 
76  * 9     2/02/99 11:36a Dave
77  * Removed obsolete data reference.
78  * 
79  * 8     12/18/98 1:13a Dave
80  * Rough 1024x768 support for Direct3D. Proper detection and usage through
81  * the launcher.
82  * 
83  * 7     11/20/98 11:16a Dave
84  * Fixed up IPX support a bit. Making sure that switching modes and
85  * loading/saving pilot files maintains proper state.
86  * 
87  * 6     11/19/98 4:19p Dave
88  * Put IPX sockets back in psnet. Consolidated all multiplayer config
89  * files into one.
90  * 
91  * 5     11/05/98 5:55p Dave
92  * Big pass at reducing #includes
93  * 
94  * 4     10/13/98 9:28a Dave
95  * Started neatening up freespace.h. Many variables renamed and
96  * reorganized. Added AlphaColors.[h,cpp]
97  * 
98  * 3     10/09/98 2:57p Dave
99  * Starting splitting up OS stuff.
100  * 
101  * 2     10/07/98 10:53a Dave
102  * Initial checkin.
103  * 
104  * 1     10/07/98 10:49a Dave
105  * 
106  * 27    7/08/98 11:56a Dave
107  * Changed mic problem error message.
108  * 
109  * 26    6/12/98 7:13p Hoffoss
110  * Fixed options screen problem where it wasn't showing tooltips.
111  * 
112  * 25    6/09/98 10:31a Hoffoss
113  * Created index numbers for all xstr() references.  Any new xstr() stuff
114  * added from here on out should be added to the end if the list.  The
115  * current list count can be found in FreeSpace.cpp (search for
116  * XSTR_SIZE).
117  * 
118  * 24    6/01/98 11:43a John
119  * JAS & MK:  Classified all strings for localization.
120  * 
121  * 23    5/21/98 9:45p Dave
122  * Lengthened tracker polling times. Put in initial support for PXO
123  * servers with channel filters. Fixed several small UI bugs.
124  * 
125  * 22    5/20/98 2:24a Dave
126  * Fixed server side voice muting. Tweaked multi debrief/endgame
127  * sequencing a bit. Much friendlier for stats tossing/accepting now.
128  * 
129  * 21    5/19/98 1:35a Dave
130  * Tweaked pxo interface. Added rankings url to pxo.cfg. Make netplayer
131  * local options update dynamically in netgames.
132  * 
133  * 20    5/18/98 12:03p Frank
134  * Make sure network changes made in options screen are loaded into any
135  * current Net_player as well as the Player.
136  * 
137  * 19    5/11/98 11:39p Dave
138  * Stuff.
139  * 
140  * 18    5/10/98 7:05p Dave
141  * Fix endgame sequencing ESC key. Changed how host options warning popups
142  * are done. Fixed pause/message scrollback/options screen problems in mp.
143  * Make sure observer HUD doesn't try to lock weapons.
144  * 
145  * 17    5/08/98 7:08p Dave
146  * Lots of UI tweaking.
147  * 
148  * 16    5/08/98 5:04p Dave
149  * Go to the join game screen when quitting multiplayer. Fixed mission
150  * text chat bugs. Put mission type symbols on the create game list.
151  * Started updating standalone gui controls.
152  * 
153  * 15    5/07/98 12:57a Dave
154  * Fixed incorrect calls to free() from stats code. Put in new artwork for
155  * debrief and host options screens. Another modification to scoring
156  * system for secondary weapons.
157  * 
158  * 14    5/06/98 8:06p Dave
159  * Made standalone reset properly under weird conditions. Tweak
160  * optionsmulti screen. Upped MAX_WEAPONS to 350. Put in new launch
161  * countdown anim. Minro ui fixes/tweaks.
162  * 
163  * 13    5/02/98 5:38p Dave
164  * Put in new tracker API code. Put in ship information on mp team select
165  * screen. Make standalone server name permanent. Fixed standalone server
166  * text messages.
167  * 
168  * 12    4/30/98 5:24p Adam
169  * JAS: Made multi config specify path.
170  * 
171  * 11    4/28/98 5:13p Dave
172  * Remove references to old MT API
173  * 
174  * 10    4/25/98 2:00p Dave
175  * Installed a bunch of multiplayer context help screens. Reworked ingame
176  * join ship select screen. Fix places where network timestamps get hosed.
177  * 
178  * 9     4/22/98 4:09p John
179  * String externalization
180  * 
181  * 8     4/22/98 12:34a Dave
182  * Make sure hud config and control config buttons draw properly in all
183  * tab modes. Make small tab buttons light up correctly in multi options
184  * screen.
185  * 
186  * 7     4/21/98 4:44p Dave
187  * Implement Vasudan ships in multiplayer. Added a debug function to bash
188  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
189  * problem in options screen. 
190  * 
191  * 6     4/20/98 6:04p Dave
192  * Implement multidata cache flushing and xferring mission files to
193  * multidata. Make sure observers can't change hud config. Fix pilot image
194  * viewing in popup. Put in game status field. Tweaked multi options. 
195  * 
196  * 5     4/18/98 12:45p Dave
197  * Aesthetic changes to multi options screen. Put in missing exit button.
198  * oops.
199  * 
200  * 4     4/17/98 6:33p Dave
201  * Finished first run of the screen. About time.
202  * 
203  * 3     4/17/98 5:27p Dave
204  * More work on the multi options screen. Fixed many minor ui todo bugs.
205  * 
206  * 2     4/17/98 12:42a Dave
207  * Worked on voice tab. Need to implement mic testing and player muting
208  * list thingie.
209  * 
210  * 1     4/16/98 11:39p Dave
211  *  
212  * 
213  * $NoKeywords: $
214  */
215
216 #include "ui.h"
217 #include "bmpman.h"
218 #include "cfile.h"
219 #include "key.h"
220 #include "ds.h"
221 #include "font.h"
222 #include "gamesnd.h"
223 #include "freespace.h"
224 #include "player.h"
225 #include "multi.h"
226 #include "multi_voice.h"
227 #include "rtvoice.h"
228 #include "mouse.h"
229 #include "optionsmenu.h"
230 #include "optionsmenumulti.h"
231 #include "popup.h"
232 #include "osregistry.h"
233 #include "alphacolors.h"
234 #include "timer.h"
235 #include "gamesequence.h"  // needed for FS1
236
237 // general data section ------------------------------------------------
238 UI_WINDOW *Om_window = NULL;
239
240 #ifndef FS1_DEMO
241 static char* Om_background_0_fname[GR_NUM_RESOLUTIONS] = {
242         "OptionsMultiGen",                      // GR_640
243         "2_OptionsMultiGen"                     // GR_1024
244 };
245
246 static char* Om_background_0_mask_fname[GR_NUM_RESOLUTIONS] = {
247         "OptionsMultiGen-M",                    // GR_640
248         "2_OptionsMultiGen-M"           // GR_1024
249 };
250
251 static char* Om_background_1_fname[GR_NUM_RESOLUTIONS] = {
252         "OptionsMultiVox",                      // GR_640
253         "2_OptionsMultiVox"                     // GR_1024
254 };
255
256 static char* Om_background_1_mask_fname[GR_NUM_RESOLUTIONS] = {
257         "OptionsMultiVox-M",                    // GR_640
258         "2_OptionsMultiVox-M"           // GR_1024
259 };
260
261 int Om_background_0 = -1;
262 int Om_mask_0             = -1;
263
264 int Om_background_1 = -1;
265 int Om_mask_1       = -1;
266 #endif  // FS1_DEMO
267
268 // screen modes
269 #define OM_MODE_NONE                                                                    -1              // no mode (unintialized)
270 #define OM_MODE_GENERAL                                                         0               // general tab
271 #define OM_MODE_VOX                                                                     1               // voice tab
272 int Om_mode = OM_MODE_NONE;
273
274 // notification stuff
275 #define OM_NOTIFY_TIME                                                          8000
276 #define OM_NOTIFY_Y                                                                     430
277 #define OM_NOTIFY_Y2                                                                    440
278 int Om_notify_stamp = -1;
279 char Om_notify_string[255];
280
281 // load all background bitmaps
282 void options_multi_load_bmaps();
283
284 // unload all the background bitmaps
285 void options_multi_unload_bmaps();
286
287 // add a notification message
288 void options_multi_add_notify(char *str);
289
290 // process and blit any notification messages
291 void options_multi_notify_process();
292
293
294 // protocol options section -------------------------------------------
295 #ifdef MAKE_FS1
296 #define OM_PRO_NUM_BUTTONS                                                      12
297
298 #define ABORT_GAME_BUTTON                                                       0
299 #define CONTROL_CONFIG_BUTTON                                           1
300 #define HUD_CONFIG_BUTTON                                                       2
301 #define OM_PRO_SCROLL_IP_UP                                                     3
302 #define OM_PRO_SCROLL_IP_DOWN                                           4
303 #define OM_PRO_ADD_IP                                                           5
304 #define OM_PRO_DELETE_IP                                                        6
305 #define OM_PRO_LOCAL_BROADCAST_YES                                      7
306 #define OM_PRO_LOCAL_BROADCAST_NO                                       8
307 #define OM_PRO_VMT                                                                      9
308 #define OM_PRO_VOX_TAB                                                          10
309 #define OM_PRO_GEN_TAB                                                          11
310 #else
311 #define OM_PRO_NUM_BUTTONS                                                              10
312
313 #define OM_PRO_TCP                                                                              0
314 #define OM_PRO_IPX                                                                              1
315 #define OM_PRO_SCROLL_IP_UP                                                     2
316 #define OM_PRO_SCROLL_IP_DOWN                                                   3
317 #define OM_PRO_ADD_IP                                                                   4
318 #define OM_PRO_DELETE_IP                                                                5
319 #define OM_PRO_LOCAL_BROADCAST                                          6
320 #define OM_PRO_VMT                                                                              7
321 #define OM_PRO_VOX_TAB                                                                  8
322 #define OM_PRO_GEN_TAB                                                                  9
323 #endif
324
325 ui_button_info Om_pro_buttons[GR_NUM_RESOLUTIONS][OM_PRO_NUM_BUTTONS] = {
326         { // GR_640
327 #ifdef MAKE_FS1
328                 ui_button_info("OPb_04",        6,              377,    -1,     -1,     4),             // Exit Game
329                 ui_button_info("OPb_05",        448,    335,    -1,     -1,     5),             // Control Config
330                 ui_button_info("OPb_06",        541,    335,    -1,     -1,     6),             // HUD Config
331
332                 ui_button_info("OPb_87",        252,    129,    -1,     -1,     87),    // Scroll IP Up
333                 ui_button_info("OPb_88",        252,    166,    -1,     -1,     88),    // Scroll IP Down
334                 ui_button_info("OPb_85",        26,             131,    -1,     -1,     85),    // Add IP
335                 ui_button_info("OPb_86",        26,             166,    -1,     -1,     86),    // Remove IP
336                 ui_button_info("OPb_89",        26,             221,    -1,     -1,     89),    // Local Broadcast Yes
337                 ui_button_info("OPb_90",        104,    221,    -1,     -1,     90),    // Local Broadcast No
338                 ui_button_info("OPb_91",        26,             243,    -1,     -1,     91),    // Parallax Online
339                 ui_button_info("OPb_92",        402,    72,     -1,     -1,     92),            // Voice Tab
340                 ui_button_info("OPb_93",        487,    72,     -1,     -1,     93),            // General Tab
341 #else
342                 ui_button_info("OMuB_07",       7,              66,     -1,     -1,     7),
343                 ui_button_info("OMuB_08",       7,              84,     -1,     -1,     8),
344                 ui_button_info("OMuB_09",       1,              124,    -1,     -1,     9),
345                 ui_button_info("OMuB_10",       1,              157,    -1,     -1,     10),
346                 ui_button_info("OMuB_11",       20,     207,    -1,     -1,     11),
347                 ui_button_info("OMuB_12",       64,     207,    -1,     -1,     12),
348                 ui_button_info("OMuB_13",       9,              251,    -1,     -1,     13),
349                 ui_button_info("OMuB_14",       9,              282,    -1,     -1,     14),
350                 ui_button_info("OMuB_15",       610,    53,     -1,     -1,     15),
351                 ui_button_info("OMuB_16",       610,    72,     -1,     -1,     16),
352 #endif
353         },
354         { // GR_1024
355                 ui_button_info("2_OMuB_07",     12,     105,    -1,     -1,     7),
356                 ui_button_info("2_OMuB_08",     12,     134,    -1,     -1,     8),
357                 ui_button_info("2_OMuB_09",     2,              198,    -1,     -1,     9),
358                 ui_button_info("2_OMuB_10",     2,              252,    -1,     -1,     10),
359                 ui_button_info("2_OMuB_11",     32,     332,    -1,     -1,     11),
360                 ui_button_info("2_OMuB_12",     103,    332,    -1,     -1,     12),
361                 ui_button_info("2_OMuB_13",     14,     402,    -1,     -1,     13),
362                 ui_button_info("2_OMuB_14",     14,     452,    -1,     -1,     14),
363                 ui_button_info("2_OMuB_15",     976,    85,     -1,     -1,     15),
364                 ui_button_info("2_OMuB_16",     976,    114,    -1,     -1,     16),
365 #ifdef MAKE_FS1
366                 // filler for extra FS1 buttons
367                 ui_button_info("none",          -1,     -1,     -1,     -1,     -1),
368                 ui_button_info("none",          -1,     -1,     -1,     -1,     -1),
369 #endif
370         }
371 };
372
373 UI_GADGET Om_pro_bogus;
374
375 // test
376 #ifdef MAKE_FS1
377 #define OM_PRO_NUM_TEXT         0
378 #else
379 #define OM_PRO_NUM_TEXT         12
380 #endif
381 UI_XSTR Om_pro_text[GR_NUM_RESOLUTIONS][OM_PRO_NUM_TEXT] = {
382         { // GR_640
383                 // not needed for FS1
384 #ifndef MAKE_FS1
385                 { "TCP",                                1378,   38,     70,     UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_TCP].button },
386                 { "IPX",                                1379,   38,     88,     UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_IPX].button },
387                 { "IP Address", 1380,   30,     128,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
388                 { "add",                                1381,   22,     235,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_ADD_IP].button },
389                 { "rem.",                       1382,   68,     235,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_DELETE_IP].button },
390                 { "Broadcast Locally",  1397,   42,     260,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_LOCAL_BROADCAST].button },   
391                 { "PXO",                                1383,   42,     291,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_VMT].button },
392                 { "Login",                      1384,   14,     309,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
393                 { "Password",           1385,   14,     336,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
394                 { "Squadron",           1386,   14,     363,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
395                 { "Voice",                      1528,   557,    60,     UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_VOX_TAB].button },
396                 { "General",            1388,   542,    77,     UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[0][OM_PRO_GEN_TAB].button },   
397 #endif
398         },
399         { // GR_1024
400                 // not needed for FS1
401 #ifndef MAKE_FS1
402                 { "TCP",                                1378,   61,     113,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_TCP].button },
403                 { "IPX",                                1379,   61,     141,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_IPX].button },
404                 { "IP Address", 1380,   47,     206,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
405                 { "add",                                1381,   36,     375,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_ADD_IP].button },
406                 { "rem.",                       1382,   109,    375,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_DELETE_IP].button },
407                 { "Broadcast Locally",  1397,   68,     417,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_LOCAL_BROADCAST].button },   
408                 { "PXO",                                1383,   68,     467,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_VMT].button },
409                 { "Login",                      1384,   23,     495,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
410                 { "Password",           1385,   23,     538,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
411                 { "Squadron",           1386,   23,     582,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_bogus },
412                 { "Voice",                      1528,   921,    96,     UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_VOX_TAB].button },
413                 { "General",            1388,   902,    123,    UI_XSTR_COLOR_GREEN, -1, &Om_pro_buttons[1][OM_PRO_GEN_TAB].button },   
414 #endif
415         }
416 };
417
418 // defines for the tracker input boxes
419 int Om_tracker_login_coords[GR_NUM_RESOLUTIONS][4] = {
420         {
421 #ifdef MAKE_FS1
422                 62, 284, 175, -1
423 #else
424                 19, 322, 226, -1                // GR_640
425 #endif
426         },
427         {
428                 31, 518, 361, -1                // GR_1024
429         }
430 };
431 int Om_tracker_passwd_coords[GR_NUM_RESOLUTIONS][4] = {
432         {
433 #ifdef MAKE_FS1
434                 62, 328, 175, -1
435 #else
436                 19, 350, 226, -1                // GR_640
437 #endif
438         },
439         {
440                 31, 562, 361, -1                // GR_1024
441         }
442 };
443 int Om_tracker_squad_name_coords[GR_NUM_RESOLUTIONS][4] = {
444         {
445                 19, 378, 226, -1                // GR_640
446         },
447         {
448                 31, 607, 361, -1                // GR_1024
449         }
450 };
451
452 // protocol section tracker login input box
453 UI_INPUTBOX Om_tracker_login;
454
455 // protocol section tracker passwd input box
456 UI_INPUTBOX Om_tracker_passwd;
457
458 // pxo squad name/password
459 UI_INPUTBOX Om_tracker_squad_name;
460
461 #define TRACKER_FOCUS_NONE                      0
462 #define TRACKER_FOCUS_LOGIN             1
463 #define TRACKER_FOCUS_PASSWORD  2
464 #define TRACKER_FOCUS_SQUADRON  3
465 static int Om_tracker_focus = 0;
466
467 // ip address list vars
468 #define IP_STRING_LEN                                                           255
469 #define MAX_IP_ADDRS                                                                    100
470
471 #define IP_EMPTY_STRING                                                         ""
472
473 int Ip_list_coords[GR_NUM_RESOLUTIONS][4] = {
474         {
475 #ifdef MAKE_FS1
476                 106, 147, 141, 48
477 #else
478                 29, 137, 227, 67                // GR_640
479 #endif
480         },
481         {
482                 46, 220, 364, 106               // GR_1024
483         }
484 };
485
486
487 int Ip_list_max_display[GR_NUM_RESOLUTIONS] = {
488         5,
489         5
490 };
491
492 static int Ip_input_coords[GR_NUM_RESOLUTIONS][4] = {
493         {
494 #ifdef MAKE_FS1
495                 107, 138, 140, -1
496 #else
497                 109, 128, 140, -1               // GR_640
498 #endif
499         },
500         {
501                 132, 206, 261, -1               // GR_640
502         }
503 };
504
505 int Om_input_mode = 0;
506 int Om_ip_start;                                                                                                // index of the first element to be displayed in the list box
507 int Om_ip_selected;                                        // the selected default IP address
508 int Om_ip_disp_count;                              // how many items are currently being displayed
509 int Om_num_ips;                                                                                         // # of ip addresses we have
510 char Om_ip_addrs[MAX_IP_ADDRS][IP_STRING_LEN];          // the ip addresses themselves
511 UI_BUTTON Om_ip_button;                                                                         // button for detecting clicks on the ip address list
512 UI_INPUTBOX Om_ip_input;                                                                        // input box for adding new ip addresses
513
514 // setting vars
515 int Om_local_broadcast;                                                                         // whether the player has local broadcast selected or not
516 int Om_tracker_flag;                                                                                    // if the guy has the tracker selected
517 int Om_protocol;                                                                                                // protocol in use
518
519 // load all the controls for the protocol section
520 void options_multi_load_protocol_controls();
521
522 // disable/hide all the controls for the protocol section
523 void options_multi_disable_protocol_controls();
524
525 // enable/unhide all the controls for the protocol section
526 void options_multi_enable_protocol_controls();
527
528 // intialize the protocol section vars
529 void options_multi_init_protocol_vars();
530
531 // do frame for the protocol section
532 void options_multi_protocol_do(int key);
533
534 // if the accept button was hit
535 void options_multi_protocol_accept();
536
537 // check for button presses
538 void options_multi_protocol_check_buttons();
539
540 // if a button was pressed
541 void options_multi_protocol_button_pressed(int n);
542
543 // load the ip address file
544 void options_multi_protocol_load_ip_file();
545
546 // save the ip address file
547 void options_multi_protocol_save_ip_file();
548
549 // draw the list of ip addresses
550 void options_multi_protocol_display_ips();
551
552 // scroll the list of ip addresses down
553 void options_multi_protocol_scroll_ip_down();
554
555 // scroll the list of ip addresses up
556 void options_multi_protocol_scroll_ip_up();
557
558 // check the ip list to see if the user has selected a new item
559 void options_multi_protocol_check_ip_list();
560
561 // delete the currently selected ip if any
562 void options_multi_protocol_delete_ip();
563
564 // attempt to add the currently entered ip address
565 void options_multi_protocol_add_current_ip();
566
567
568 // general options tab section -------------------------------------------
569 #define OM_GEN_NUM_BUTTONS                                                              10
570
571 #define OM_GEN_OBJ_LOW                                                                  0
572 #define OM_GEN_OBJ_MED                                                                  1
573 #define OM_GEN_OBJ_HIGH                                                                 2
574 #define OM_GEN_OBJ_LAN                                                                  3
575 #define OM_GEN_PIX_YES                                                                  4
576 #define OM_GEN_PIX_NO                                                                   5
577 #define OM_GEN_XFER_MULTIDATA_YES                                       6
578 #define OM_GEN_XFER_MULTIDATA_NO                                                7
579 #define OM_GEN_FLUSH_NO                                                                 8
580 #define OM_GEN_FLUSH_YES                                                                9
581
582 ui_button_info Om_gen_buttons[GR_NUM_RESOLUTIONS][OM_GEN_NUM_BUTTONS] = {
583         { // GR_640
584 #ifdef MAKE_FS1
585                 ui_button_info("OPb_94",        410,    121,    -1,     -1,     94),
586                 ui_button_info("OPb_95",        410,    143,    -1,     -1,     95),
587                 ui_button_info("OPb_96",        410,    165,    -1,     -1,     96),
588                 ui_button_info("none",          -1,             -1,             -1,     -1,     -1),    // no LAN setting in FS1
589                 ui_button_info("OPb_97",        410,    199,    -1,     -1,     97),
590                 ui_button_info("OPb_98",        496,    199,    -1,     -1,     98),
591                 ui_button_info("OPb_99",        410,    233,    -1,     -1,     99),
592                 ui_button_info("OPb_100",       410,    256,    -1,     -1,     100),
593                 ui_button_info("OPb_101",       410,    290,    -1,     -1,     101),
594                 ui_button_info("OPb_102",       410,    313,    -1,     -1,     102),
595 #else
596                 ui_button_info("OGB_17",        598,    117,    -1,     -1,     17),
597                 ui_button_info("OGB_18",        598,    139,    -1,     -1,     18),
598                 ui_button_info("OGB_19",        598,    161,    -1,     -1,     19),
599                 ui_button_info("OGB_20",        598,    183,    -1,     -1,     20),
600                 ui_button_info("OGB_21",        549,    229,    -1,     -1,     21),
601                 ui_button_info("OGB_22",        598,    229,    -1,     -1,     22),
602                 ui_button_info("OGB_23",        598,    286,    -1,     -1,     23),
603                 ui_button_info("OGB_24",        598,    307,    -1,     -1,     24),
604                 ui_button_info("OGB_25",        598,    347,    -1,     -1,     25),
605                 ui_button_info("OGB_26",        598,    368,    -1,     -1,     26),
606 #endif
607         },
608         { // GR_1024
609                 ui_button_info("2_OGB_17",      957,    188,    -1,     -1,     17),
610                 ui_button_info("2_OGB_18",      957,    223,    -1,     -1,     18),
611                 ui_button_info("2_OGB_19",      957,    258,    -1,     -1,     19),
612                 ui_button_info("2_OGB_20",      957,    293,    -1,     -1,     20),
613                 ui_button_info("2_OGB_21",      879,    366,    -1,     -1,     21),
614                 ui_button_info("2_OGB_22",      957,    366,    -1,     -1,     22),
615                 ui_button_info("2_OGB_23",      957,    457,    -1,     -1,     23),
616                 ui_button_info("2_OGB_24",      957,    491,    -1,     -1,     24),
617                 ui_button_info("2_OGB_25",      957,    555,    -1,     -1,     25),
618                 ui_button_info("2_OGB_26",      957,    589,    -1,     -1,     26),
619         }
620 };
621
622 UI_GADGET Om_gen_bogus;
623
624 // text
625 #ifdef MAKE_FS1
626 #define OM_GEN_NUM_TEXT                                 0
627 #else
628 #define OM_GEN_NUM_TEXT                                 14
629 #endif
630 UI_XSTR Om_gen_text[GR_NUM_RESOLUTIONS][OM_GEN_NUM_TEXT] = {
631         { // GR_640
632                 // not needed for FS1
633 #ifndef MAKE_FS1
634                 { "Object Update",      1391,           511,    104,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
635                 { "Low",                                        1160,           558,    127,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_OBJ_LOW].button },
636                 { "Medium",                             1161,           538,    149,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_OBJ_MED].button },            
637                 { "High",                               1162,           556,    171,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_OBJ_HIGH].button },           
638                 { "Lan",                                        1392,           561,    193,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_OBJ_LAN].button },            
639                 { "Pilot / Squad Images",       1393,           463,    214,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
640                 { "Yes",                                        1394,           555,    257,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_PIX_YES].button },            
641                 { "No",                                 1395,           604,    257,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_PIX_NO].button },             
642                 { "Transfer Missions",          1396,           478,    271,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
643                 { "/multidata",         1397,           519,    292,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_XFER_MULTIDATA_YES].button },         
644                 { "/missions",                  1398,           527,    314,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_XFER_MULTIDATA_NO].button },          
645                 { "Flush Cache",                1399,           529,    334,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
646                 { "Never",                              1400,           548,    355,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_FLUSH_NO].button },           
647                 { "Before Game",                1401,           502,    377,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[0][OM_GEN_FLUSH_YES].button },          
648 #endif
649         },
650         { // GR_1024
651                 // not needed for FS1
652 #ifndef MAKE_FS1
653                 { "Object Update",      1391,           818,    166,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
654                 { "Low",                                        1160,           913,    204,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_OBJ_LOW].button },
655                 { "Medium",                             1161,           892,    239,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_OBJ_MED].button },            
656                 { "High",                               1162,           909,    274,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_OBJ_HIGH].button },           
657                 { "Lan",                                        1392,           916,    310,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_OBJ_LAN].button },            
658                 { "Pilot / Squad Images",       1393,           821,    345,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
659                 { "Yes",                                        1394,           887,    411,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_PIX_YES].button },            
660                 { "No",                                 1395,           966,    411,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_PIX_NO].button },             
661                 { "Transfer Missions",          1396,           844,    435,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
662                 { "/multidata",         1397,           858,    468,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_XFER_MULTIDATA_YES].button },         
663                 { "/missions",                  1398,           870,    503,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_XFER_MULTIDATA_NO].button },          
664                 { "Flush Cache",                1399,           886,    533,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_bogus },                
665                 { "Never",                              1400,           897,    568,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_FLUSH_NO].button },           
666                 { "Before Game",                1401,           849,    603,    UI_XSTR_COLOR_GREEN,    -1,     &Om_gen_buttons[1][OM_GEN_FLUSH_YES].button },          
667 #endif
668         }
669 };
670
671 // setting vars
672 int Om_gen_obj_update;                                                          // object update level
673 int Om_gen_pix;                                                                         // accept pilot pix or not
674 int Om_gen_xfer_multidata;                                                      // xfer missions to multidata or not
675 int Om_gen_flush_cache;                                                         // flush multidata directory before every game
676
677 // load all the general tab controls
678 void options_multi_load_gen_controls();
679
680 // disable/hide all the general tab controls
681 void options_multi_disable_gen_controls();
682
683 // enable/unhide all the general tab controls
684 void options_multi_enable_gen_controls();
685
686 // initialize the general tab vars
687 void options_multi_init_gen_vars();
688
689 // accept function for the general tab
690 void options_multi_gen_accept();
691
692 // do frame for the general tab
693 void options_multi_gen_do();
694
695 // check for button presses
696 void options_multi_gen_check_buttons();
697
698 // a button was pressed
699 void options_multi_gen_button_pressed(int n);
700
701
702 // voice options tab section -------------------------------------------
703 #define OM_VOX_NUM_BUTTONS                                                              6
704
705 #define OM_VOX_VOICE_TEST                                                               0
706 #define OM_VOX_VOICE_YES                                                                1
707 #define OM_VOX_VOICE_NO                                                                 2
708 #define OM_VOX_PLIST_UP                                                                 3
709 #define OM_VOX_PLIST_DOWN                                                               4
710 #define OM_VOX_VOICE_MUTE                                                               5
711
712 UI_GADGET Om_vox_bogus;
713
714 ui_button_info Om_vox_buttons[GR_NUM_RESOLUTIONS][OM_VOX_NUM_BUTTONS] = {
715         { // GR_640
716 #ifdef MAKE_FS1
717                 ui_button_info("OPb_103",       413,    110,    -1,     -1,     103),
718                 ui_button_info("OPb_105",       413,    186,    -1,     -1,     105),
719                 ui_button_info("OPb_106",       491,    186,    -1,     -1,     106),
720                 ui_button_info("OPb_108",       413,    253,    -1,     -1,     108),
721                 ui_button_info("OPb_109",       413,    291,    -1,     -1,     109),
722                 ui_button_info("OPb_107",       413,    229,    -1,     -1,     107),
723 #else
724                 ui_button_info("OVB_17",        562,    118,    -1,     -1,     17),
725                 ui_button_info("OVB_19",        551,    208,    -1,     -1,     19),
726                 ui_button_info("OVB_20",        599,    208,    -1,     -1,     20),
727                 ui_button_info("OVB_21",        614,    256,    -1,     -1,     21),
728                 ui_button_info("OVB_22",        614,    290,    -1,     -1,     22),
729                 ui_button_info("OVB_23",        599,    354,    -1,     -1,     23),
730 #endif
731         },
732         { // GR_640
733                 ui_button_info("2_OVB_17",      900,    189,    -1,     -1,     17),
734                 ui_button_info("2_OVB_19",      882,    333,    -1,     -1,     19),
735                 ui_button_info("2_OVB_20",      959,    333,    -1,     -1,     20),
736                 ui_button_info("2_OVB_21",      983,    410,    -1,     -1,     21),
737                 ui_button_info("2_OVB_22",      983,    464,    -1,     -1,     22),
738                 ui_button_info("2_OVB_23",      959,    566,    -1,     -1,     23),
739         }
740 };
741
742 // text
743 #ifdef MAKE_FS1
744 #define OM_VOX_NUM_TEXT                                 0
745 #else
746 #define OM_VOX_NUM_TEXT                                 6
747 #endif
748 UI_XSTR Om_vox_text[GR_NUM_RESOLUTIONS][OM_VOX_NUM_TEXT] = {
749         { // GR_640
750                 // not needed for FS1
751 #ifndef MAKE_FS1
752                 { "Mic test",                           1389,           567,    104,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[0][OM_VOX_VOICE_TEST].button },
753                 { "Voice Quality",              1531,           439,    149,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_bogus },
754                 { "Voice Transmission", 1530,           439,    193,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_bogus },
755                 { "On",                                         1285,           556,    233,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[0][OM_VOX_VOICE_YES].button },
756                 { "Off",                                                1286,           604,    233,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[0][OM_VOX_VOICE_NO].button },
757                 { "Mute",                                       1390,           594,    381,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[0][OM_VOX_VOICE_MUTE].button },
758 #endif
759         },
760         { // GR_1024
761                 // not needed for FS1
762 #ifndef MAKE_FS1
763                 { "mic test",                           1389,           908,    166,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[1][OM_VOX_VOICE_TEST].button },
764                 { "Voice Quality",              1531,           703,    239,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_bogus },
765                 { "Voice Transmission", 1530,           783,    310,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_bogus },
766                 { "On",                                         1285,           890,    373,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[1][OM_VOX_VOICE_YES].button },
767                 { "Off",                                                1286,           967,    373,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[1][OM_VOX_VOICE_NO].button },
768                 { "Mute",                                       1390,           950,    609,    UI_XSTR_COLOR_GREEN,    -1, &Om_vox_buttons[1][OM_VOX_VOICE_MUTE].button },
769 #endif
770         }
771 };
772
773 #define NUM_OM_VOX_SLIDERS                              1
774 #define OM_VOX_QOS_SLIDER                               0
775
776 op_sliders Om_vox_sliders[GR_NUM_RESOLUTIONS][NUM_OM_VOX_SLIDERS] = {
777         { // GR_640                             
778 #ifdef MAKE_FS1
779                 op_sliders("OPb_104",   413,    151,    -1,     -1,     104,    20,     10,     NULL, -1,       -1,     -1,     NULL,   -1,     -1,     -1),
780 #else
781                 op_sliders("OVB_18",    429,    162,    -1,     -1,     18,     20,     10, NULL, -1, -1, -1, NULL, -1, -1, -1),        // voice QOS
782 #endif
783         },      
784         { // GR_1024                            
785                 op_sliders("2_OVB_18",  686,    259,    -1,     -1,     18,     20,     10, NULL, -1, -1, -1, NULL, -1, -1, -1),        // voice QOS
786         }
787 };
788
789 // player list area
790 int Om_vox_plist_coords[GR_NUM_RESOLUTIONS][4] = {
791         {       // GR_640
792 #ifdef MAKE_FS1
793                 445, 260, 142, 61
794 #else
795                 377, 270, 232, 79
796 #endif
797         },
798         {       // GR_1024
799                 604, 432, 371, 127
800         }
801 };
802 int Om_vox_plist_max_display[GR_NUM_RESOLUTIONS] = {
803         6,
804         6
805 };
806
807 int Om_vox_plist_start;
808 UI_BUTTON Om_vox_plist_button;
809
810 // voice test buffer
811 #define OM_VOX_BUF_SIZE                         (1<<12)
812 #define OM_VOX_COMP_SIZE                        ((1<<15) + (1<<14))
813
814 #define OM_VOX_WAVE_Y                           240
815 #define OM_VOX_WAVE_WIDTH                       300
816
817 #define OM_VOX_DROP_ICON_X                      100
818 #define OM_VOX_DROP_ICON_Y                      100
819
820 #define OM_VOX_RECORD_INT                       175
821
822 unsigned char Om_vox_voice_buffer[OM_VOX_BUF_SIZE];
823 int Om_vox_voice_buffer_size = -1;
824
825 unsigned char Om_vox_comp_buffer[OM_VOX_COMP_SIZE];
826 int Om_vox_voice_comp_size = -1;
827
828 int Om_vox_playback_handle;
829
830 // status of any test voice recording
831 #define OM_VOX_TEST_NONE                                        -1
832 #define OM_VOX_TEST_RECORDING                           0
833 #define OM_VOX_TEST_PLAYBACK                            1
834 int Om_vox_test_status = OM_VOX_TEST_NONE;
835
836 // setting vars
837 int Om_vox_accept_voice;
838
839 // simple list of players we are looking through
840 net_player *Om_vox_players[MAX_PLAYERS];
841
842 // selected player
843 net_player *Om_vox_player_select;
844
845 // mute or don't mute for each player
846 int Om_vox_player_flags[MAX_PLAYERS];
847
848 // the # of players
849 int Om_vox_num_players;
850
851 // load all the voice tab controls
852 void options_multi_load_vox_controls();
853
854 // disable/hide all the voice tab controls
855 void options_multi_disable_vox_controls();
856
857 // enable/unhide all the voice tab controls
858 void options_multi_enable_vox_controls();
859
860 // initialize the voice tab vars
861 void options_multi_init_vox_vars();
862
863 // accept function for the voice tab
864 void options_multi_vox_accept();
865
866 // do frame for the voice tab
867 void options_multi_vox_do();
868
869 // check for button presses
870 void options_multi_vox_check_buttons();
871
872 // a button was pressed
873 void options_multi_vox_button_pressed(int n);
874
875 // process/display the player list
876 void options_multi_vox_process_player_list();
877
878 // scroll the player list down
879 void options_multi_vox_plist_scroll_down();
880
881 // scroll the player list up
882 void options_multi_vox_plist_scroll_up();
883
884 // get the index into the player list of the passed netplayer
885 int options_multi_vox_plist_get(net_player *pl);
886
887
888 // general data section ------------------------------------------------
889
890 // load all background bitmaps
891 void options_multi_load_bmaps()
892 {
893 #ifndef FS1_DEMO
894         // load both background bitmaps
895         Om_background_0 = bm_load(Om_background_0_fname[gr_screen.res]);
896         if(Om_background_0 == -1){
897                 nprintf(("Network","Error loading options background %s\n",Om_background_0_fname[gr_screen.res]));
898         }
899
900         Om_background_1 = bm_load(Om_background_1_fname[gr_screen.res]);
901         if(Om_background_1 == -1){
902                 nprintf(("Network","Error loading options background %s\n",Om_background_1_fname[gr_screen.res]));
903         }
904
905         // load in both mask bitmaps
906         Om_mask_0 = bm_load(Om_background_0_mask_fname[gr_screen.res]);
907         if(Om_mask_0 == -1){
908                 nprintf(("Network","Error loading options background mask %s\n",Om_background_0_mask_fname[gr_screen.res]));
909         }
910
911         Om_mask_1 = bm_load(Om_background_1_mask_fname[gr_screen.res]);
912         if(Om_mask_1 == -1){
913                 nprintf(("Network","Error loading options background mask %s\n",Om_background_1_mask_fname[gr_screen.res]));
914         }
915 #endif
916 }
917
918 // unload all the background bitmaps
919 void options_multi_unload_bmaps()
920 {
921 #ifndef FS1_DEMO
922         // unload all background bitmaps
923         if(Om_background_0 != -1){
924                 bm_release(Om_background_0);
925                 Om_background_0 = -1;
926         } 
927         if(Om_background_1 != -1){
928                 bm_release(Om_background_1);
929                 Om_background_1 = -1;
930         }
931
932         // unload all mask bitmaps
933         if(Om_mask_0 != -1){
934                 bm_release(Om_mask_0);
935                 Om_mask_0 = -1;
936         }
937         if(Om_mask_1 != -1){
938                 bm_release(Om_mask_1);
939                 Om_mask_1 = -1;
940         }
941 #endif
942 }
943
944 // add a notification message
945 void options_multi_add_notify(char *str)
946 {
947         // copy the string
948         memset(Om_notify_string,0,255);
949         if(str != NULL){                
950                 strcpy(Om_notify_string,str);
951         }               
952
953         // set the timestamp
954         Om_notify_stamp = timestamp(OM_NOTIFY_TIME);
955 }
956
957 // process and blit any notification messages
958 void options_multi_notify_process()
959 {
960         int w;
961         char *p_str[3];
962         int n_chars[3];
963         char line[255];
964         int line_count;
965         int y_start;
966         int idx;
967         
968         // if there is no timestamp, do nothing
969         if(Om_notify_stamp == -1){
970                 return;
971         }
972
973         // otherwise, if it has elapsed, unset it
974         if(timestamp_elapsed(Om_notify_stamp)){
975                 Om_notify_stamp = -1;
976                 return;
977         }
978
979         // otherwise display the string
980         line_count = split_str(Om_notify_string, 600, n_chars, p_str, 3);       
981         y_start = OM_NOTIFY_Y;
982         gr_set_color_fast(&Color_bright);
983         for(idx=0;idx<line_count;idx++){
984                 memset(line, 0, 255);
985                 strncpy(line, p_str[idx], n_chars[idx]);
986                                 
987                 gr_get_string_size(&w,NULL,line);
988                 gr_string((600 - w)/2,y_start,line);
989
990                 y_start += 10;
991         }       
992 }
993
994
995 // protocol section --------------------------------------------------------
996
997 // load all the controls for the protocol section
998 void options_multi_load_protocol_controls()
999 {
1000         int idx;
1001         
1002         Assert(Om_window != NULL);
1003
1004         // instantiate all the buttons
1005         for(idx=0; idx<OM_PRO_NUM_BUTTONS; idx++){
1006                 // create the object
1007                 Om_pro_buttons[gr_screen.res][idx].button.create(Om_window, "", Om_pro_buttons[gr_screen.res][idx].x, Om_pro_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
1008
1009                 // set the sound to play when highlighted
1010                 Om_pro_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1011
1012                 // set the ani for the button
1013                 Om_pro_buttons[gr_screen.res][idx].button.set_bmaps(Om_pro_buttons[gr_screen.res][idx].filename);
1014
1015                 // set the hotspot
1016                 Om_pro_buttons[gr_screen.res][idx].button.link_hotspot(Om_pro_buttons[gr_screen.res][idx].hotspot);
1017         }
1018
1019         // text
1020         for(idx=0; idx<OM_PRO_NUM_TEXT; idx++){
1021                 Om_window->add_XSTR(&Om_pro_text[gr_screen.res][idx]);
1022         }
1023
1024         // create the tracker input boxes       
1025         Om_tracker_login.create(Om_window, Om_tracker_login_coords[gr_screen.res][0], Om_tracker_login_coords[gr_screen.res][1], Om_tracker_login_coords[gr_screen.res][2], LOGIN_LEN - 1, Multi_tracker_login, UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_NO_BACK);
1026         Om_tracker_passwd.create(Om_window, Om_tracker_passwd_coords[gr_screen.res][0], Om_tracker_passwd_coords[gr_screen.res][1], Om_tracker_passwd_coords[gr_screen.res][2], 1, Multi_tracker_passwd, UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_PASSWD | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_NO_BACK);
1027         Om_tracker_squad_name.create(Om_window, Om_tracker_squad_name_coords[gr_screen.res][0], Om_tracker_squad_name_coords[gr_screen.res][1], Om_tracker_squad_name_coords[gr_screen.res][2], LOGIN_LEN - 1, Multi_tracker_squad_name, UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_NO_BACK);
1028
1029         // create the invisible button for checking for clicks on the ip address list
1030         Om_ip_button.create(Om_window, "", Ip_list_coords[gr_screen.res][0], Ip_list_coords[gr_screen.res][1], Ip_list_coords[gr_screen.res][2], Ip_list_coords[gr_screen.res][3], 0, 1);
1031         Om_ip_button.hide();
1032
1033         // create the new ip address input box  
1034         Om_ip_input.create(Om_window, Ip_input_coords[gr_screen.res][0], Ip_input_coords[gr_screen.res][1], Ip_input_coords[gr_screen.res][2], IP_STRING_LEN, IP_EMPTY_STRING, UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_KEYTHRU);
1035         Om_ip_input.hide();
1036         Om_ip_input.disable();
1037         
1038         // disable IPX button in demo
1039 #ifdef FS2_DEMO
1040         Om_pro_buttons[gr_screen.res][OM_PRO_IPX].button.disable();
1041         Om_pro_buttons[gr_screen.res][OM_PRO_IPX].button.hide();
1042 #endif
1043
1044         // bogus control
1045         Om_pro_bogus.base_create(Om_window, UI_KIND_ICON, 0, 0, 0, 0);
1046 }
1047
1048 // disable/hide all the controls for the protocol section
1049 void options_multi_disable_protocol_controls()
1050 {
1051         int idx;
1052         
1053         // hide and disable all the protocol buttons
1054         for(idx=0;idx<OM_PRO_NUM_BUTTONS;idx++){
1055                 // hide the button
1056                 Om_pro_buttons[gr_screen.res][idx].button.hide();
1057
1058                 // disable the button
1059                 Om_pro_buttons[gr_screen.res][idx].button.disable();
1060         }
1061
1062         // hide and disable the tracker input boxes
1063         Om_tracker_login.hide();
1064         Om_tracker_login.disable();
1065         Om_tracker_passwd.hide();
1066         Om_tracker_passwd.disable();
1067         Om_tracker_squad_name.hide();
1068         Om_tracker_squad_name.disable();
1069
1070         // disable the click detection button
1071         Om_ip_button.disable();
1072
1073         // disable and hide the ip address inputbox
1074         Om_ip_input.hide();
1075         Om_ip_input.disable();
1076
1077         // undo input mode if necessary
1078         Om_input_mode = 0;
1079
1080         // bogus control
1081         Om_pro_bogus.hide();
1082         Om_pro_bogus.disable();
1083 }
1084
1085 // enable/unhide all the controls for the protocol section
1086 void options_multi_enable_protocol_controls()
1087 {
1088         int idx;
1089         
1090         // unhide and enable all the protocol buttons
1091         for(idx=0;idx<OM_PRO_NUM_BUTTONS;idx++){
1092                 // enable the button
1093                 Om_pro_buttons[gr_screen.res][idx].button.enable();
1094                 
1095                 // unhide the button
1096                 Om_pro_buttons[gr_screen.res][idx].button.unhide();             
1097         }
1098
1099         // unhide and enable the tracker input boxes
1100         if(Om_tracker_flag){
1101                 Om_tracker_login.enable();      
1102                 Om_tracker_passwd.enable();
1103                 Om_tracker_squad_name.enable();
1104         }
1105         Om_tracker_login.unhide();
1106         Om_tracker_passwd.unhide();
1107         Om_tracker_squad_name.unhide();
1108
1109         // enable the click detection button
1110         Om_ip_button.enable();  
1111
1112         // bogus control
1113         Om_pro_bogus.enable();
1114         Om_pro_bogus.unhide();  
1115 }
1116
1117 // intialize the protocol section vars
1118 void options_multi_init_protocol_vars()
1119 {
1120         // current protocol
1121         Om_protocol = Multi_options_g.protocol;
1122
1123         // whether or not the user has the local broadcast button selected
1124         Om_local_broadcast = (Player->m_local_options.flags & MLO_FLAG_LOCAL_BROADCAST) ? 1 : 0;
1125
1126         // whether or not we're playing on the tracker
1127         Om_tracker_flag = 0; // (Multi_options_g.protocol == NET_TCP) && Multi_options_g.pxo ? 1 : 0;   
1128
1129         // load the ip address list     
1130         Om_ip_disp_count = 0;
1131         options_multi_protocol_load_ip_file();
1132         Om_ip_selected = Om_num_ips - 1;        
1133         Om_ip_start = Om_num_ips - 1;                   
1134 }
1135
1136 // do frame for the protocol section
1137 void options_multi_protocol_do(int key)
1138 {
1139         // check for button presses
1140         options_multi_protocol_check_buttons();
1141         
1142         // force draw the correct "local broadcast" button      
1143         if(Om_local_broadcast){
1144 #ifdef MAKE_FS1
1145                 Om_pro_buttons[gr_screen.res][OM_PRO_LOCAL_BROADCAST_YES].button.draw_forced(2);
1146         } else {
1147                 Om_pro_buttons[gr_screen.res][OM_PRO_LOCAL_BROADCAST_NO].button.draw_forced(2);
1148 #else
1149                 Om_pro_buttons[gr_screen.res][OM_PRO_LOCAL_BROADCAST].button.draw_forced(2);
1150 #endif
1151         }
1152
1153         // draw the "vmt" button if it is selected
1154         if(Om_tracker_flag){
1155                 Om_pro_buttons[gr_screen.res][OM_PRO_VMT].button.draw_forced(2);
1156         }
1157
1158         // see if he hit any interesting key presses
1159         switch(key){
1160         case KEY_ENTER:
1161                 // add a new ip string if we're in "input" mode
1162                 if(Om_input_mode){                      
1163                         options_multi_protocol_add_current_ip();
1164                         
1165                         // clear the text control and input mode
1166                         Om_ip_input.set_text("");
1167                         Om_ip_input.clear_focus();
1168                         Om_ip_input.disable();
1169                         Om_input_mode = 0;
1170                 }
1171
1172                 // if the tracker login inputbox has focus, lose it
1173                 if(Om_tracker_login.has_focus()){
1174                         Om_tracker_login.clear_focus();
1175                         gamesnd_play_iface(SND_COMMIT_PRESSED);
1176                 }
1177                 // if the tracker password inputbox has focus, lose it
1178                 if(Om_tracker_passwd.has_focus()){
1179                         Om_tracker_passwd.clear_focus();
1180                         gamesnd_play_iface(SND_COMMIT_PRESSED);
1181                 }
1182                 // if the tracker squad name inputbox has focus, lose it
1183                 if(Om_tracker_squad_name.has_focus()){
1184                         Om_tracker_squad_name.clear_focus();
1185                         gamesnd_play_iface(SND_COMMIT_PRESSED);
1186                 }
1187                 break;
1188
1189         case KEY_ESC:
1190                 // if we're in input mode, cancel out
1191                 if(Om_input_mode){
1192                         // clear the text control and input mode
1193                         Om_ip_input.set_text("");
1194                         Om_ip_input.clear_focus();
1195                         Om_ip_input.disable();
1196                         Om_input_mode = 0;
1197                 }
1198                 // otherwise quit the options screen altogether
1199                 else {
1200                         options_cancel_exit();
1201                 }
1202                 break;
1203
1204         case KEY_TAB:
1205                 // tab through the tracker input controls
1206                 if(Om_tracker_login.has_focus()){
1207                         Om_tracker_passwd.set_focus();
1208                 } else if(Om_tracker_passwd.has_focus()){
1209                         Om_tracker_squad_name.set_focus();
1210                 } else if(Om_tracker_squad_name.has_focus()){
1211                         Om_tracker_login.set_focus();
1212                 }
1213                 break;
1214         }
1215
1216         // force draw the proper protocol
1217 #ifndef MAKE_FS1        // not in FS1 menu
1218         if (Om_protocol == NET_IPX) {
1219                 Om_pro_buttons[gr_screen.res][OM_PRO_IPX].button.draw_forced(2);
1220         } else {
1221                 Om_pro_buttons[gr_screen.res][OM_PRO_TCP].button.draw_forced(2);
1222         }
1223 #endif
1224
1225         // force draw the proper tab button
1226         switch (Om_mode) {
1227         case OM_MODE_GENERAL:
1228                 Om_pro_buttons[gr_screen.res][OM_PRO_GEN_TAB].button.draw_forced(2);
1229                 break;
1230
1231         case OM_MODE_VOX:
1232                 Om_pro_buttons[gr_screen.res][OM_PRO_VOX_TAB].button.draw_forced(2);
1233                 break;
1234         }
1235
1236         // check to see if the user has clicked on the ip list and selected a new item
1237         options_multi_protocol_check_ip_list();
1238
1239         // draw the list of ip addresses
1240         options_multi_protocol_display_ips();   
1241
1242         // hack to play sound when input boxes gain focus
1243         if (Om_tracker_login.has_focus()) {
1244                 if (Om_tracker_focus != TRACKER_FOCUS_LOGIN) {
1245                         Om_tracker_focus = TRACKER_FOCUS_LOGIN;
1246                         gamesnd_play_iface(SND_USER_SELECT);
1247                 }
1248         } else if (Om_tracker_passwd.has_focus()) {
1249                 if (Om_tracker_focus != TRACKER_FOCUS_PASSWORD) {
1250                         Om_tracker_focus = TRACKER_FOCUS_PASSWORD;
1251                         gamesnd_play_iface(SND_USER_SELECT);
1252                 }
1253         } else if (Om_tracker_squad_name.has_focus()) {
1254                 if (Om_tracker_focus != TRACKER_FOCUS_SQUADRON) {
1255                         Om_tracker_focus = TRACKER_FOCUS_SQUADRON;
1256                         gamesnd_play_iface(SND_USER_SELECT);
1257                 }
1258         } else {
1259                 Om_tracker_focus = TRACKER_FOCUS_NONE;
1260         }
1261 }
1262
1263 // if the accept button was hit
1264 void options_multi_protocol_accept()
1265 {
1266         // if the user has selected local broadcast write it into his options struct
1267         Player->m_local_options.flags &= ~(MLO_FLAG_LOCAL_BROADCAST);
1268         if(Om_local_broadcast){
1269                 Player->m_local_options.flags |= MLO_FLAG_LOCAL_BROADCAST;
1270         }       
1271
1272         // active protocol
1273         Multi_options_g.protocol = Om_protocol;
1274
1275         // copy the VMT login and password data
1276         Om_tracker_login.get_text(Multi_tracker_login);
1277         Om_tracker_passwd.get_text(Multi_tracker_passwd);
1278         Om_tracker_squad_name.get_text(Multi_tracker_squad_name);
1279
1280         // write out the tracker login and passwd values to the registry
1281         os_config_write_string( "PXO", "Login", Multi_tracker_login );
1282         os_config_write_string( "PXO", "Password", Multi_tracker_passwd );
1283
1284         // write out the PXO squad name and passwd values to the registry
1285         os_config_write_string( "PXO", "SquadName", Multi_tracker_squad_name );
1286         
1287         // save the ip address list
1288         options_multi_protocol_save_ip_file();
1289 }
1290
1291 // check for button presses
1292 void options_multi_protocol_check_buttons()
1293 {
1294         int idx;
1295
1296         // go through each button
1297         for(idx=0;idx<OM_PRO_NUM_BUTTONS;idx++){
1298                 if(Om_pro_buttons[gr_screen.res][idx].button.pressed()){
1299                         options_multi_protocol_button_pressed(idx);
1300                         break;
1301                 }
1302         }
1303 }
1304
1305 // if a button was pressed
1306 void options_multi_protocol_button_pressed(int n)
1307 {
1308 #ifdef MAKE_FS1
1309         int choice;
1310 #endif
1311
1312         switch(n){
1313         // add an ip address
1314         case OM_PRO_ADD_IP:
1315                 // don't process if we're in input mode
1316                 if(Om_input_mode){
1317                         break;
1318                 }
1319
1320                 // setup the input mode
1321                 Om_input_mode = 1;
1322                 Om_ip_input.enable();
1323                 Om_ip_input.unhide();
1324                 Om_ip_input.set_text(IP_EMPTY_STRING);
1325                 Om_ip_input.set_focus();
1326                 gamesnd_play_iface(SND_USER_SELECT);
1327                 break;
1328
1329         // delete the currently selected ip
1330         case OM_PRO_DELETE_IP:
1331                 // don't process if we're in input mode
1332                 if(Om_input_mode){
1333                         break;
1334                 }
1335
1336                 options_multi_protocol_delete_ip();
1337                 gamesnd_play_iface(SND_USER_SELECT);
1338                 break;
1339
1340         // the "local" broadcast button - toggle
1341 #ifdef MAKE_FS1
1342         // Yes and No buttons in FS1
1343         case OM_PRO_LOCAL_BROADCAST_YES:
1344                 if(Om_input_mode){
1345                         break;
1346                 }
1347
1348                 Om_local_broadcast = 1;
1349
1350                 gamesnd_play_iface(SND_USER_SELECT);
1351                 break;
1352
1353         case OM_PRO_LOCAL_BROADCAST_NO:
1354                 if(Om_input_mode){
1355                         break;
1356                 }
1357
1358                 Om_local_broadcast = 0;
1359
1360                 gamesnd_play_iface(SND_USER_SELECT);
1361                 break;
1362 #else
1363         case OM_PRO_LOCAL_BROADCAST:
1364                 // don't process if we're in input mode
1365                 if(Om_input_mode){
1366                         break;
1367                 }
1368
1369                 if(!Om_local_broadcast){                        
1370                         Om_local_broadcast = 1;
1371                 } else {
1372                         Om_local_broadcast = 0;
1373                 }
1374
1375                 gamesnd_play_iface(SND_USER_SELECT);
1376                 break;
1377 #endif
1378
1379         // scroll ips down
1380         case OM_PRO_SCROLL_IP_DOWN:             
1381                 // don't process if we're in input mode
1382                 if(Om_input_mode){
1383                         break;
1384                 }
1385
1386                 options_multi_protocol_scroll_ip_down();
1387                 break;
1388
1389         // scroll ips up
1390         case OM_PRO_SCROLL_IP_UP:               
1391                 // don't process if we're in input mode
1392                 if(Om_input_mode){
1393                         break;
1394                 }
1395
1396                 options_multi_protocol_scroll_ip_up();
1397                 break;
1398
1399         // the vmt button
1400         case OM_PRO_VMT:
1401                 // for the multiplayer beta, always force tracker mode
1402 #ifdef MULTIPLAYER_BETA_BUILD // do we want this for FS2_DEMO
1403                 Om_tracker_flag = 1;
1404 #else
1405                 // don't process if we're in input mode
1406                 if(Om_input_mode){
1407                         break;
1408                 }
1409
1410                 // toggle the stupid thing
1411                 Om_tracker_flag = !Om_tracker_flag;
1412
1413                 // if the thing is toggled on - enable the inputbox controls, else diable them
1414                 if(Om_tracker_flag){
1415                         Om_tracker_login.enable();
1416                         Om_tracker_passwd.enable();
1417                         Om_tracker_squad_name.enable();
1418                 } else {
1419                         Om_tracker_login.disable();
1420                         Om_tracker_passwd.disable();
1421                         Om_tracker_squad_name.disable();
1422                 }
1423
1424                 // play a sound
1425                 gamesnd_play_iface(SND_USER_SELECT);
1426 #endif
1427                 break;
1428
1429         // general tab button 
1430 #ifndef FS1_DEMO
1431         case OM_PRO_GEN_TAB:    
1432                 if(Om_mode != OM_MODE_GENERAL){
1433                         // set the general tab
1434                         Om_mode = OM_MODE_GENERAL;              
1435
1436                         // disable the voice controls
1437                         options_multi_disable_vox_controls();
1438
1439                         // enable the general controls
1440                         options_multi_enable_gen_controls();
1441
1442                         // set the general screen mask  
1443                         Assert(Om_mask_0 >= 0);
1444                         Om_window->set_mask_bmap(Om_mask_0, Om_background_0_mask_fname[gr_screen.res]);
1445                 }
1446
1447                 // play a sound
1448                 gamesnd_play_iface(SND_USER_SELECT);
1449
1450                 break;
1451
1452         // voice tab button
1453         case OM_PRO_VOX_TAB:
1454                 if(Om_mode != OM_MODE_VOX){
1455                         // set the voice tab
1456                         Om_mode = OM_MODE_VOX;
1457
1458                         // disable the general controls
1459                         options_multi_disable_gen_controls();
1460
1461                         // enable the voice controls
1462                         options_multi_enable_vox_controls();
1463
1464                         // set the voice screen mask    
1465                         Assert(Om_mask_1 >= 0);
1466                         Om_window->set_mask_bmap(Om_mask_1, Om_background_1_mask_fname[gr_screen.res]);
1467                 }
1468                 // play a sound
1469                 gamesnd_play_iface(SND_USER_SELECT);
1470
1471                 break;
1472 #endif  // FS1_DEMO
1473
1474         // tcp mode
1475 #ifndef MAKE_FS1        // not in FS1 option menu
1476         case OM_PRO_TCP:
1477                 Om_protocol = NET_TCP;
1478                 gamesnd_play_iface(SND_USER_SELECT);
1479                 break;
1480
1481         // ipx mode
1482         case OM_PRO_IPX:
1483 #ifndef FS2_DEMO
1484                 Om_protocol = NET_IPX;
1485                 gamesnd_play_iface(SND_USER_SELECT);
1486 #endif
1487                 break;
1488 #endif
1489
1490 #ifdef MAKE_FS1
1491         case ABORT_GAME_BUTTON:
1492                 gamesnd_play_iface(SND_USER_SELECT);
1493                 choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR("Exit Game?", 374));
1494                 if ( choice == 1 )
1495                         gameseq_post_event(GS_EVENT_QUIT_GAME);
1496                 break;
1497 #endif
1498         }
1499 }
1500
1501 // load the ip address file
1502 void options_multi_protocol_load_ip_file()
1503 {
1504         char line[IP_STRING_LEN];
1505         CFILE *file = NULL;
1506
1507         // reset the ip address count
1508         Om_num_ips = 0;
1509
1510         // attempt to open the ip list file
1511         file = cfopen(IP_CONFIG_FNAME,"rt",CFILE_NORMAL,CF_TYPE_DATA);  
1512         if(file == NULL){
1513                 nprintf(("Network","Error loading tcp.cfg file!\n"));
1514                 return;
1515         }
1516
1517         // read in all the strings in the file
1518         while(!cfeof(file)){
1519                 line[0] = '\0';
1520                 cfgets(line,IP_STRING_LEN,file);
1521
1522                 // strip off any newline character
1523                 if(line[strlen(line) - 1] == '\n'){
1524                         line[strlen(line) - 1] = '\0';
1525                 }
1526
1527                 // 0 length lines don't get processed
1528                 if((line[0] == '\0') || (line[0] == '\n') )
1529                         continue;
1530
1531                 if ( !psnet_is_valid_ip_string(line) ) {
1532                         nprintf(("Network","Invalid ip string (%s)\n",line));
1533                 } else {
1534                         if(Om_num_ips < MAX_IP_ADDRS-1){
1535                                 strcpy(Om_ip_addrs[Om_num_ips++],line);
1536                         }
1537                 }
1538         }
1539
1540         cfclose(file);
1541 }
1542
1543 // save the ip address file
1544 void options_multi_protocol_save_ip_file()
1545 {
1546         int idx;
1547         CFILE *file = NULL;
1548
1549         // attempt to open the ip list file for writing
1550         file = cfopen(IP_CONFIG_FNAME,"wt",CFILE_NORMAL,CF_TYPE_DATA );
1551         if(file == NULL){
1552                 nprintf(("Network","Error loading tcp.cfg file\n"));
1553                 return;
1554         }
1555
1556         // write out all the string we have
1557         for(idx=0;idx<Om_num_ips;idx++){
1558                 // make _absolutely_ sure its a valid address
1559                 // MWA -- commented out next line because name resolution might fail when
1560                 // it was added.  We'll only grab games that we can actually get to.
1561                 //Assert(psnet_is_valid_ip_string(Multi_ip_addrs[idx]));
1562
1563                 cfputs(Om_ip_addrs[idx],file);
1564                                 
1565            // make sure to tack on a newline if necessary
1566                 if(Om_ip_addrs[idx][strlen(&Om_ip_addrs[idx][0]) - 1] != '\n'){
1567                         cfputs(NOX("\n"),file);
1568                 }
1569         }
1570
1571         cfclose(file);
1572 }
1573
1574 // draw the list of ip addresses
1575 void options_multi_protocol_display_ips()
1576 {
1577         int idx;
1578         int y_start = Ip_list_coords[gr_screen.res][1];
1579                 
1580         // get the # of items we should be displaying based upon the # of addresses and the starting display point
1581         if(Om_ip_start >= Ip_list_max_display[gr_screen.res]){
1582                 Om_ip_disp_count = Ip_list_max_display[gr_screen.res];
1583         } else {
1584                 Om_ip_disp_count = Om_ip_start + 1;
1585         }
1586         
1587         // display the addresses
1588         for(idx=Om_ip_start; idx >= Om_ip_start - Om_ip_disp_count + 1 ; idx--){        
1589                 if(idx == Om_ip_selected){
1590                         gr_set_color_fast(&Color_bright);
1591                 } else {
1592                         gr_set_color_fast(&Color_white);
1593                 }
1594
1595                 gr_printf(Ip_list_coords[gr_screen.res][0], y_start, Om_ip_addrs[idx]);
1596                 y_start += 10;
1597         }
1598 }
1599
1600 // scroll the list of ip addresses down
1601 void options_multi_protocol_scroll_ip_down()
1602 {
1603         if(Om_ip_start >= Ip_list_max_display[gr_screen.res]){
1604                 gamesnd_play_iface(SND_SCROLL);
1605                 Om_ip_start--;
1606         } else {
1607                 gamesnd_play_iface(SND_GENERAL_FAIL);
1608         }       
1609 }
1610
1611 // scroll the list of ip addresses up
1612 void options_multi_protocol_scroll_ip_up()
1613 {
1614         if(Om_ip_start < Om_num_ips-1){
1615                 gamesnd_play_iface(SND_SCROLL);
1616                 Om_ip_start++;
1617         } else {
1618                 gamesnd_play_iface(SND_GENERAL_FAIL);
1619         }
1620 }
1621
1622 // check the ip list to see if the user has selected a new item
1623 void options_multi_protocol_check_ip_list()
1624 {
1625         int click_y;    
1626         int item;
1627         
1628         if(Om_ip_button.pressed()){
1629                 // determine which item he clicked on   
1630                 Om_ip_button.get_mouse_pos(NULL, &click_y);
1631                 item = click_y / 10;
1632                         
1633                 // determine if there is an item in this location, and select it if so
1634                 if(item < Om_ip_disp_count){
1635                         Om_ip_selected = Om_ip_start - item;
1636                 }
1637         }
1638 }
1639
1640 // delete the currently selected ip if any
1641 void options_multi_protocol_delete_ip()
1642 {
1643         int idx;
1644         
1645         // attempt to delete the currently highlighted item
1646         if(Om_ip_selected != -1){               
1647
1648                 // move down all the other items                                
1649                 for(idx=Om_ip_selected; idx < Om_num_ips; idx++){
1650                         strcpy(Om_ip_addrs[idx],Om_ip_addrs[idx+1]);
1651                 }
1652
1653                 // make sure to decrement the starting index
1654                 Om_ip_start--;                  
1655                         
1656                 // check to make sure that the selected item is valid                   
1657                 Om_num_ips--;                   
1658                 if(Om_num_ips <= 0){
1659                         Om_ip_selected = -1;
1660                 } else {
1661                         if(Om_ip_selected > 0){
1662                                 Om_ip_selected--;       
1663                         } 
1664                 }                                               
1665         }
1666 }
1667
1668 // return 10, if successflu
1669 char Ip_str[IP_STRING_LEN+1];
1670 int Ip_validated_already = 0;
1671 int options_multi_verify_ip()
1672 {
1673         int result;
1674
1675         if(!Ip_validated_already){
1676                 // see if its a valid ip address
1677                 result = psnet_is_valid_ip_string(Ip_str);
1678         
1679                 // if the result is a valid ip string, return immediately
1680                 if(result){
1681                         return 10;
1682                 }
1683
1684                 // otherwise, change the popup text to indicate that it is invalid and wait for the user to click ok
1685                 popup_change_text(XSTR( "Ip string is invalid!", 386));
1686         }       
1687
1688         Ip_validated_already = 1;
1689
1690         // always wait for the user to hit the "cancel" button
1691         return 0;
1692 }
1693
1694 // attempt to add the currently entered ip address
1695 void options_multi_protocol_add_current_ip()
1696 {               
1697         // get the entered string
1698         Om_ip_input.get_text(Ip_str);
1699
1700         // this popup wil do several things. 
1701         // 1.) It will display a popup so the user isn't left scratching his head
1702         // 2.) If the address
1703         Ip_validated_already = 0;
1704         if(popup_till_condition(options_multi_verify_ip, XSTR( "Cancel", 387), XSTR( "Verifying ip address", 388)) == 10){
1705                 if(Om_num_ips < MAX_IP_ADDRS){
1706                         strcpy(Om_ip_addrs[Om_num_ips],Ip_str);
1707                         Om_ip_start = Om_num_ips;
1708                         Om_num_ips++;
1709                         
1710                         // if this is the first item on the list, select it
1711                         if(Om_num_ips == 1){
1712                                 Om_ip_selected = 0;
1713                         }
1714                 } else {
1715                         options_multi_add_notify(XSTR( "Max # of IP addresses reached!", 389));
1716                 }
1717         }                       
1718 }
1719
1720 // general options tab section -------------------------------------------
1721
1722 // load all the general tab controls
1723 void options_multi_load_gen_controls()
1724 {
1725         int idx;
1726         
1727         Assert(Om_window != NULL);
1728
1729         // instantiate all the buttons
1730         for(idx=0; idx<OM_GEN_NUM_BUTTONS; idx++){                              
1731                 // create the object
1732                 Om_gen_buttons[gr_screen.res][idx].button.create(Om_window, "", Om_gen_buttons[gr_screen.res][idx].x, Om_gen_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
1733
1734                 // set the sound to play when highlighted
1735                 Om_gen_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
1736
1737                 // set the ani for the button
1738                 Om_gen_buttons[gr_screen.res][idx].button.set_bmaps(Om_gen_buttons[gr_screen.res][idx].filename);
1739
1740                 // set the hotspot
1741                 Om_gen_buttons[gr_screen.res][idx].button.link_hotspot(Om_gen_buttons[gr_screen.res][idx].hotspot);
1742         }
1743
1744         // text
1745         for(idx=0; idx<OM_GEN_NUM_TEXT; idx++){
1746                 Om_window->add_XSTR(&Om_gen_text[gr_screen.res][idx]);
1747         }
1748
1749         // bogus control
1750         Om_gen_bogus.base_create(Om_window, UI_KIND_ICON, 0, 0, 0, 0);
1751 }
1752
1753 // disable/hide all the general tab controls
1754 void options_multi_disable_gen_controls()
1755 {
1756         int idx;
1757
1758         // go through all the controls
1759         for(idx=0;idx<OM_GEN_NUM_BUTTONS;idx++){
1760                 Om_gen_buttons[gr_screen.res][idx].button.hide();
1761                 Om_gen_buttons[gr_screen.res][idx].button.disable();
1762         }
1763
1764         // bogus control
1765         Om_gen_bogus.hide();
1766         Om_gen_bogus.disable();
1767 }
1768
1769 // enable/unhide all the general tab controls
1770 void options_multi_enable_gen_controls()
1771 {
1772         int idx;
1773
1774         // go through all the controls
1775         for(idx=0;idx<OM_GEN_NUM_BUTTONS;idx++){                
1776                 Om_gen_buttons[gr_screen.res][idx].button.enable();
1777                 Om_gen_buttons[gr_screen.res][idx].button.unhide();
1778         }
1779
1780         // bogus control
1781         Om_gen_bogus.enable();
1782         Om_gen_bogus.unhide();
1783 }
1784
1785 // initialize the general tab vars
1786 void options_multi_init_gen_vars()
1787 {
1788         // initialize the object update
1789         Om_gen_obj_update = Player->m_local_options.obj_update_level;
1790
1791         // initialize the accept pix var        
1792         if(Player->m_local_options.flags & MLO_FLAG_ACCEPT_PIX){
1793                 Om_gen_pix = 1;
1794         } else {
1795                 Om_gen_pix = 0;
1796         }
1797
1798         // initialize the xfer_multidata var
1799         if(Player->m_local_options.flags & MLO_FLAG_XFER_MULTIDATA){
1800                 Om_gen_xfer_multidata = 1;
1801         } else {
1802                 Om_gen_xfer_multidata = 0;
1803         }
1804
1805         // initialize the flush cache var
1806         if(Player->m_local_options.flags & MLO_FLAG_FLUSH_CACHE){
1807                 Om_gen_flush_cache = 1;
1808         } else {
1809                 Om_gen_flush_cache = 0;
1810         }
1811 }
1812
1813 // accept function for the general tab
1814 void options_multi_gen_accept()
1815 {
1816         // apply the object update level
1817         Player->m_local_options.obj_update_level = Om_gen_obj_update;
1818
1819         // apply the accept pix var
1820         Player->m_local_options.flags &= ~(MLO_FLAG_ACCEPT_PIX);
1821         if(Om_gen_pix){
1822                 Player->m_local_options.flags |= MLO_FLAG_ACCEPT_PIX;
1823         }
1824
1825         // apply the xfer multidata var
1826         Player->m_local_options.flags &= ~(MLO_FLAG_XFER_MULTIDATA);
1827         if(Om_gen_xfer_multidata){
1828                 Player->m_local_options.flags |= MLO_FLAG_XFER_MULTIDATA;
1829         } 
1830
1831         // apply the flush cache var
1832         Player->m_local_options.flags &= ~(MLO_FLAG_FLUSH_CACHE);
1833         if(Om_gen_flush_cache){
1834                 Player->m_local_options.flags |= MLO_FLAG_FLUSH_CACHE;
1835         }
1836 }
1837
1838 // do frame for the general tab
1839 void options_multi_gen_do()
1840 {
1841         // check for button presses
1842         options_multi_gen_check_buttons();
1843
1844         // draw the proper object update button
1845         switch(Om_gen_obj_update){
1846         case OBJ_UPDATE_LOW:
1847                 Om_gen_buttons[gr_screen.res][OM_GEN_OBJ_LOW].button.draw_forced(2);
1848                 break;
1849         case OBJ_UPDATE_MEDIUM:
1850                 Om_gen_buttons[gr_screen.res][OM_GEN_OBJ_MED].button.draw_forced(2);
1851                 break;
1852         case OBJ_UPDATE_HIGH:
1853                 Om_gen_buttons[gr_screen.res][OM_GEN_OBJ_HIGH].button.draw_forced(2);
1854                 break;
1855         case OBJ_UPDATE_LAN:
1856                 Om_gen_buttons[gr_screen.res][OM_GEN_OBJ_LAN].button.draw_forced(2);
1857                 break;
1858         default :
1859                 Int3();
1860         }
1861
1862         // draw the proper pix button
1863         if(Om_gen_pix){
1864                 Om_gen_buttons[gr_screen.res][OM_GEN_PIX_YES].button.draw_forced(2);
1865         } else {
1866                 Om_gen_buttons[gr_screen.res][OM_GEN_PIX_NO].button.draw_forced(2);
1867         }
1868
1869         // draw the proper xfer multidata button
1870         if(Om_gen_xfer_multidata){
1871                 Om_gen_buttons[gr_screen.res][OM_GEN_XFER_MULTIDATA_YES].button.draw_forced(2);
1872         } else {
1873                 Om_gen_buttons[gr_screen.res][OM_GEN_XFER_MULTIDATA_NO].button.draw_forced(2);
1874         }
1875
1876         // draw the proper flush cache button
1877         if(Om_gen_flush_cache){
1878                 Om_gen_buttons[gr_screen.res][OM_GEN_FLUSH_YES].button.draw_forced(2);
1879         } else {
1880                 Om_gen_buttons[gr_screen.res][OM_GEN_FLUSH_NO].button.draw_forced(2);
1881         }
1882 }
1883
1884 // check for button presses
1885 void options_multi_gen_check_buttons()
1886 {
1887         int idx;
1888
1889         // go through all the buttons
1890         for(idx=0;idx<OM_GEN_NUM_BUTTONS;idx++){
1891                 if(Om_gen_buttons[gr_screen.res][idx].button.pressed()){
1892                         options_multi_gen_button_pressed(idx);
1893                         break;
1894                 }
1895         }
1896 }
1897
1898 // a button was pressed
1899 void options_multi_gen_button_pressed(int n)
1900 {
1901         switch(n){
1902         // low object update level
1903         case OM_GEN_OBJ_LOW:
1904                 if(Om_gen_obj_update != OBJ_UPDATE_LOW){
1905                         gamesnd_play_iface(SND_USER_SELECT);
1906                         Om_gen_obj_update = OBJ_UPDATE_LOW;
1907                 } else {
1908                         gamesnd_play_iface(SND_GENERAL_FAIL);
1909                 }
1910                 break;
1911         
1912         // medium object update level
1913         case OM_GEN_OBJ_MED:
1914                 if(Om_gen_obj_update != OBJ_UPDATE_MEDIUM){
1915                         gamesnd_play_iface(SND_USER_SELECT);
1916                         Om_gen_obj_update = OBJ_UPDATE_MEDIUM;
1917                 } else {
1918                         gamesnd_play_iface(SND_GENERAL_FAIL);
1919                 }
1920                 break;
1921         
1922         // high object update level
1923         case OM_GEN_OBJ_HIGH:
1924                 if(Om_gen_obj_update != OBJ_UPDATE_HIGH){
1925                         gamesnd_play_iface(SND_USER_SELECT);
1926                         Om_gen_obj_update = OBJ_UPDATE_HIGH;
1927                 } else {
1928                         gamesnd_play_iface(SND_GENERAL_FAIL);
1929                 }
1930                 break;
1931
1932         // lan object update level
1933         case OM_GEN_OBJ_LAN:
1934                 if(Om_gen_obj_update != OBJ_UPDATE_LAN){
1935                         gamesnd_play_iface(SND_USER_SELECT);
1936                         Om_gen_obj_update = OBJ_UPDATE_LAN;
1937                 } else {
1938                         gamesnd_play_iface(SND_GENERAL_FAIL);
1939                 }
1940                 break;
1941         
1942         // accept pix
1943         case OM_GEN_PIX_YES:
1944                 if(!Om_gen_pix){
1945                         gamesnd_play_iface(SND_USER_SELECT);
1946                         Om_gen_pix = 1;
1947                 } else {
1948                         gamesnd_play_iface(SND_GENERAL_FAIL);
1949                 }
1950                 break;
1951         
1952         // don't accept pix
1953         case OM_GEN_PIX_NO:
1954                 if(Om_gen_pix){
1955                         gamesnd_play_iface(SND_USER_SELECT);
1956                         Om_gen_pix = 0;
1957                 } else {
1958                         gamesnd_play_iface(SND_GENERAL_FAIL);
1959                 }
1960                 break;
1961         
1962         // put missions in the multidate directory
1963         case OM_GEN_XFER_MULTIDATA_YES:
1964                 if(!Om_gen_xfer_multidata){
1965                         gamesnd_play_iface(SND_USER_SELECT);
1966                         Om_gen_xfer_multidata = 1;
1967                 } else {
1968                         gamesnd_play_iface(SND_GENERAL_FAIL);
1969                 }
1970                 break;
1971         
1972         // dont put missions in the multidata directory
1973         case OM_GEN_XFER_MULTIDATA_NO:
1974                 if(Om_gen_xfer_multidata){
1975                         gamesnd_play_iface(SND_USER_SELECT);
1976                         Om_gen_xfer_multidata = 0;
1977                 } else {
1978                         gamesnd_play_iface(SND_GENERAL_FAIL);
1979                 }
1980                 break;
1981         
1982         // flush the cache before each mission
1983         case OM_GEN_FLUSH_YES:
1984                 if(!Om_gen_flush_cache){
1985                         gamesnd_play_iface(SND_USER_SELECT);
1986                         Om_gen_flush_cache = 1;
1987                 } else {
1988                         gamesnd_play_iface(SND_GENERAL_FAIL);
1989                 }
1990                 break;
1991         
1992         // don't flush the cache before each mission
1993         case OM_GEN_FLUSH_NO:
1994                 if(Om_gen_flush_cache){
1995                         gamesnd_play_iface(SND_USER_SELECT);
1996                         Om_gen_flush_cache = 0;
1997                 } else {
1998                         gamesnd_play_iface(SND_GENERAL_FAIL);
1999                 }
2000                 break;  
2001         }
2002 }
2003
2004 // voice options tab section -------------------------------------------
2005
2006 // load all the voice tab controls
2007 void options_multi_load_vox_controls()
2008 {
2009         int idx;
2010         
2011         Assert(Om_window != NULL);
2012
2013         // instantiate all the buttons
2014         for(idx=0; idx<OM_VOX_NUM_BUTTONS; idx++){
2015                 // create the object
2016                 Om_vox_buttons[gr_screen.res][idx].button.create(Om_window, "", Om_vox_buttons[gr_screen.res][idx].x, Om_vox_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
2017
2018                 // set the sound to play when highlighted
2019                 Om_vox_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
2020
2021                 // set the ani for the button
2022                 Om_vox_buttons[gr_screen.res][idx].button.set_bmaps(Om_vox_buttons[gr_screen.res][idx].filename);
2023
2024                 // set the hotspot
2025                 Om_vox_buttons[gr_screen.res][idx].button.link_hotspot(Om_vox_buttons[gr_screen.res][idx].hotspot);
2026         }
2027
2028         // text
2029         for(idx=0; idx<OM_VOX_NUM_TEXT; idx++){
2030                 Om_window->add_XSTR(&Om_vox_text[gr_screen.res][idx]);
2031         }
2032         
2033         // sliders
2034         for ( idx = 0; idx < NUM_OM_VOX_SLIDERS; idx++ ) {
2035                  Om_vox_sliders[gr_screen.res][idx].slider.create(Om_window, Om_vox_sliders[gr_screen.res][idx].x, Om_vox_sliders[gr_screen.res][idx].y,
2036                                                                                                                                                 Om_vox_sliders[gr_screen.res][idx].dots, Om_vox_sliders[gr_screen.res][idx].filename,
2037                                                                                                                                                 Om_vox_sliders[gr_screen.res][idx].hotspot, Om_vox_sliders[gr_screen.res][idx].right_filename, Om_vox_sliders[gr_screen.res][idx].right_mask, Om_vox_sliders[gr_screen.res][idx].right_x, Om_vox_sliders[gr_screen.res][idx].right_y,
2038                                                                                                                                                 Om_vox_sliders[gr_screen.res][idx].left_filename, Om_vox_sliders[gr_screen.res][idx].left_mask, Om_vox_sliders[gr_screen.res][idx].left_x, Om_vox_sliders[gr_screen.res][idx].left_y,
2039                                                                                                                                                 Om_vox_sliders[gr_screen.res][idx].dot_w);
2040         }       
2041
2042         // create the player list select button
2043         Om_vox_plist_button.create(Om_window, "", Om_vox_plist_coords[gr_screen.res][0], Om_vox_plist_coords[gr_screen.res][1], Om_vox_plist_coords[gr_screen.res][2], Om_vox_plist_coords[gr_screen.res][3], 0, 1);
2044         Om_vox_plist_button.hide();
2045
2046         // build a list of net players
2047         Om_vox_num_players = 0;
2048         for(idx=0;idx<MAX_PLAYERS;idx++){
2049                 Om_vox_players[idx] = NULL;
2050
2051                 // if i'm not connected, do nothing
2052                 if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_CONNECTED)){
2053                         continue;
2054                 }
2055
2056                 // add all players I know about
2057                 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_player != &Net_players[idx])){
2058                         // set the netplayer pointer
2059                         Om_vox_players[Om_vox_num_players] = &Net_players[idx];
2060
2061                         // set his mute flag
2062                         Om_vox_player_flags[Om_vox_num_players] = (Multi_voice_local_prefs & (1<<idx)) ? 1 : 0;
2063
2064                         // increment the count
2065                         Om_vox_num_players++;
2066                 }
2067         }       
2068         
2069         // bogus control
2070         Om_vox_bogus.base_create(Om_window, UI_KIND_ICON, 0, 0, 0, 0);
2071 }
2072
2073 // disable/hide all the voice tab controls
2074 void options_multi_disable_vox_controls()
2075 {
2076         int idx;
2077
2078         // go through all the controls
2079         for(idx=0; idx<OM_VOX_NUM_BUTTONS; idx++){
2080                 Om_vox_buttons[gr_screen.res][idx].button.hide();
2081                 Om_vox_buttons[gr_screen.res][idx].button.disable();
2082         }
2083
2084         // hide the qos control
2085         Om_vox_sliders[gr_screen.res][OM_VOX_QOS_SLIDER].slider.hide();
2086         Om_vox_sliders[gr_screen.res][OM_VOX_QOS_SLIDER].slider.disable();      
2087
2088         // unset the sound buffer size so we don't display any waveforms
2089         Om_vox_voice_buffer_size = -1;
2090         Om_vox_voice_comp_size = -1;
2091         Om_vox_playback_handle = -1;
2092         Om_vox_test_status = OM_VOX_TEST_NONE;  
2093
2094         // disable the player list select button
2095         Om_vox_plist_button.disable();
2096
2097         // bogus controls
2098         Om_vox_bogus.hide();
2099         Om_vox_bogus.disable();
2100 }
2101
2102 // enable/unhide all the voice tab controls
2103 void options_multi_enable_vox_controls()
2104 {
2105         int idx;
2106
2107         // go through all the controls
2108         for(idx=0; idx<OM_VOX_NUM_BUTTONS; idx++){              
2109                 Om_vox_buttons[gr_screen.res][idx].button.enable();
2110                 Om_vox_buttons[gr_screen.res][idx].button.unhide();
2111         }
2112
2113         // unhide the qos control       
2114         Om_vox_sliders[gr_screen.res][OM_VOX_QOS_SLIDER].slider.enable();       
2115         Om_vox_sliders[gr_screen.res][OM_VOX_QOS_SLIDER].slider.unhide();       
2116
2117         // unset the sound buffer size so we don't display any waveforms
2118         Om_vox_voice_buffer_size = -1;
2119         Om_vox_voice_comp_size = -1;
2120         Om_vox_playback_handle = -1;
2121         Om_vox_test_status = OM_VOX_TEST_NONE;  
2122
2123         // select the first player on the list
2124         Om_vox_player_select = Om_vox_players[0];
2125         Om_vox_plist_start = 0;
2126
2127         // enable the player list select button
2128         Om_vox_plist_button.enable();
2129
2130         // bogus controls
2131         Om_vox_bogus.enable();
2132         Om_vox_bogus.unhide();
2133 }
2134
2135 // initialize the voice tab vars
2136 void options_multi_init_vox_vars()
2137 {
2138         // intialize the accept voice var
2139         if(Player->m_local_options.flags & MLO_FLAG_NO_VOICE){
2140                 Om_vox_accept_voice = 0;
2141         } else {
2142                 Om_vox_accept_voice = 1;
2143         }
2144 }
2145
2146 // accept function for the voice tab
2147 void options_multi_vox_accept()
2148 {
2149         int idx;
2150         int voice_pref_flags;
2151         
2152         // set the accept voice flag
2153         Player->m_local_options.flags &= ~(MLO_FLAG_NO_VOICE);
2154         if(!Om_vox_accept_voice){
2155                 Player->m_local_options.flags |= MLO_FLAG_NO_VOICE;
2156         }
2157
2158         // build the voice preferences stuff
2159         voice_pref_flags = 0xffffffff;
2160         for(idx=0;idx<Om_vox_num_players;idx++){
2161                 // if this guy is muted
2162                 if(!Om_vox_player_flags[idx]){
2163                         voice_pref_flags &= ~(1 << NET_PLAYER_INDEX(Om_vox_players[idx]));
2164                 }
2165         }
2166         multi_voice_set_prefs(voice_pref_flags);
2167 }
2168
2169 // do frame for the voice tab
2170 void options_multi_vox_do()
2171 {
2172         int handle;
2173         
2174         // check for button presses
2175         options_multi_vox_check_buttons();
2176
2177         // draw the proper accept voice button
2178         if(Om_vox_accept_voice){
2179                 Om_vox_buttons[gr_screen.res][OM_VOX_VOICE_YES].button.draw_forced(2);
2180         } else {
2181                 Om_vox_buttons[gr_screen.res][OM_VOX_VOICE_NO].button.draw_forced(2);
2182         }
2183
2184         // if the currently selected player is muted
2185         if((Om_vox_player_select != NULL) && !Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)]){
2186                 Om_vox_buttons[gr_screen.res][OM_VOX_VOICE_MUTE].button.draw_forced(2);
2187         }
2188
2189         // process and display the player list
2190         options_multi_vox_process_player_list();
2191
2192         // if we're currently doing a voice test recording, process some stuff
2193         switch(Om_vox_test_status){
2194         case OM_VOX_TEST_RECORDING:     
2195                 multi_voice_test_process();
2196
2197                 // force draw the mic test button
2198                 Om_vox_buttons[gr_screen.res][OM_VOX_VOICE_TEST].button.draw_forced(2);
2199
2200                 // if we are no longer recording, switch to playback if possible
2201                 if(!multi_voice_test_recording()){
2202                         Om_vox_test_status = OM_VOX_TEST_PLAYBACK;
2203                         
2204                         if(Om_vox_voice_comp_size != -1){
2205                                 // stop any playing back sounds
2206                                 rtvoice_stop_playback_all();
2207
2208                                 // attempt to get a playback handle
2209                                 handle = multi_voice_test_get_playback_buffer();
2210                                 if(handle != -1){
2211                                         Om_vox_playback_handle = rtvoice_play_uncompressed(handle, Om_vox_comp_buffer, Om_vox_voice_comp_size);
2212
2213                                         // mark us as playing back
2214                                         Om_vox_test_status = OM_VOX_TEST_PLAYBACK;
2215                                 }
2216                                 // on error, notify the user something is wrong
2217                                 else {
2218                                         options_multi_add_notify(XSTR( "Error trying to playback recorded voice! Check your hardware", 390));
2219
2220                                         // mark us as doing nothing
2221                                         Om_vox_test_status = OM_VOX_TEST_NONE;
2222                                 }
2223                         } else {
2224                                 // mark us as doing nothing
2225                                 Om_vox_test_status = OM_VOX_TEST_NONE;
2226                         }                       
2227                 }
2228                 break;
2229         
2230         case OM_VOX_TEST_PLAYBACK:                      
2231                 // if we were playing a sound back, but now the sound is done
2232                 if((Om_vox_playback_handle != -1) && (ds_get_play_position(ds_get_channel(Om_vox_playback_handle)) >= (DWORD)Om_vox_voice_comp_size)){
2233                         // flush all playing sounds safely
2234                         rtvoice_stop_playback_all();
2235
2236                         // null the sound handle
2237                         Om_vox_playback_handle = -1;
2238
2239                         // set this so we know not to display any more waveforms
2240                         Om_vox_voice_buffer_size = -1;
2241                         Om_vox_voice_comp_size = -1;                    
2242
2243                         // free the status up
2244                         Om_vox_test_status = OM_VOX_TEST_NONE;
2245                 }
2246                 break;
2247         }
2248 }
2249
2250 // check for button presses
2251 void options_multi_vox_check_buttons()
2252 {
2253         int idx;
2254
2255         // go through all the buttons
2256         for(idx=0; idx<OM_VOX_NUM_BUTTONS; idx++){
2257                 if(Om_vox_buttons[gr_screen.res][idx].button.pressed()){
2258                         options_multi_vox_button_pressed(idx);
2259                         break;
2260                 }
2261         }
2262 }
2263
2264 // a button was pressed
2265 void options_multi_vox_button_pressed(int n)
2266 {
2267         switch(n){
2268         // accept voice button
2269         case OM_VOX_VOICE_YES:
2270                 if(!Om_vox_accept_voice){
2271                         gamesnd_play_iface(SND_USER_SELECT);
2272                         Om_vox_accept_voice = 1;
2273                 } else {
2274                         gamesnd_play_iface(SND_GENERAL_FAIL);
2275                 }
2276                 break;
2277         
2278         // don't accept voice button
2279         case OM_VOX_VOICE_NO:
2280                 if(Om_vox_accept_voice){
2281                         gamesnd_play_iface(SND_USER_SELECT);
2282                         Om_vox_accept_voice = 0;
2283                 } else {
2284                         gamesnd_play_iface(SND_GENERAL_FAIL);
2285                 }
2286                 break;
2287
2288         // mute/unmute button
2289         case OM_VOX_VOICE_MUTE:
2290                 if(Om_vox_player_select != NULL){
2291                         Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)] = !Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)];
2292                         gamesnd_play_iface(SND_USER_SELECT);
2293                 } else {
2294                         gamesnd_play_iface(SND_GENERAL_FAIL);
2295                 }
2296                 break;
2297
2298         // scroll the player list up
2299         case OM_VOX_PLIST_UP:
2300                 options_multi_vox_plist_scroll_up();
2301                 break;
2302
2303         // scroll the player list down
2304         case OM_VOX_PLIST_DOWN:
2305                 options_multi_vox_plist_scroll_down();
2306                 break;          
2307
2308         // mic test button
2309         case OM_VOX_VOICE_TEST:
2310                 // if in a multiplayer game, don't allow testing
2311                 if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_CONNECTED)){
2312                         options_multi_add_notify(XSTR( "Cannot test mic while in a multiplayer game!", 391));
2313                         break;
2314                 }
2315
2316                 // if this machine is not capable of playing
2317                 if(!Multi_voice_can_record){
2318                         options_multi_add_notify(XSTR( "DirectSoundCapture could not be initialized. To initialize DirectSoundCapture your sound card must be full duplex and your sound card drivers must support DirectSoundCapture", 392));
2319                 } else {
2320                         // if we're not already doing a record test
2321                         if(Om_vox_test_status == OM_VOX_TEST_NONE){
2322                                 // set the quality of sound
2323                                 rtvoice_set_qos(Om_vox_sliders[gr_screen.res][OM_VOX_QOS_SLIDER].slider.pos + 1);
2324
2325                                 // clear the comp buffer
2326                                 memset(Om_vox_comp_buffer,128,OM_VOX_COMP_SIZE);
2327
2328                                 Om_vox_test_status = OM_VOX_TEST_RECORDING;
2329                                 multi_voice_test_record_start();
2330                         }
2331                 }
2332                 break;
2333         }
2334 }
2335
2336 // screen shader
2337 extern shader Grey_shader;
2338
2339 // process and blit any voice waveform if necessary
2340 void options_multi_vox_process_waveform()
2341 {
2342         int c_width = OM_VOX_WAVE_WIDTH;
2343         int avg_len;
2344         int buf_offset;
2345         int idx,a_idx,running_avg;      
2346         
2347         // if we're not in recording or playback mode
2348         if(Om_vox_test_status == OM_VOX_TEST_NONE){
2349                 return;
2350         }
2351
2352         // grey the screen
2353         gr_set_shader(&Grey_shader);
2354         gr_shade(0,0,gr_screen.clip_width, gr_screen.clip_height);
2355
2356         switch(Om_vox_test_status){
2357         case OM_VOX_TEST_RECORDING:
2358                 // if we have no sound buffer size, do nothing
2359                 if(Om_vox_voice_buffer_size <= 0){
2360                         return;
2361                 }
2362
2363                 // if we are not recording, do nothing
2364                 if(Om_vox_test_status != OM_VOX_TEST_RECORDING){
2365                         return;
2366                 }
2367
2368                 // get the # of samples we'll average for one line
2369                 avg_len = Om_vox_voice_buffer_size / c_width;
2370
2371                 // blit the waveform
2372                 gr_set_color_fast(&Color_green);
2373                 buf_offset = 0;
2374                 for(idx=0; idx < c_width; idx++){
2375                         // reset the running average
2376                         running_avg = 0;
2377                         for(a_idx = 0; a_idx < avg_len; a_idx++){
2378                                 running_avg += (int)Om_vox_voice_buffer[buf_offset] - 128;                      
2379
2380                                 // increment the buffer offset
2381                                 buf_offset++;
2382                         }
2383
2384                         running_avg /= avg_len;
2385                         gr_line((gr_screen.max_w - OM_VOX_WAVE_WIDTH)/2 + idx, OM_VOX_WAVE_Y, (gr_screen.max_w - OM_VOX_WAVE_WIDTH)/2 + idx, OM_VOX_WAVE_Y + running_avg);
2386                 }               
2387
2388                 // if this packet would have been dropped, notify the user
2389                 if(multi_voice_test_packet_tossed()){
2390                         gr_set_color_fast(&Color_bright);
2391                         gr_string(OM_VOX_DROP_ICON_X,OM_VOX_DROP_ICON_Y, XSTR( "Packet Overflow", 393));
2392                 }               
2393                 break;
2394
2395         case OM_VOX_TEST_PLAYBACK:
2396                 // get the offset into the playing direct sound buffer
2397                 buf_offset = ds_get_play_position(ds_get_channel(Om_vox_playback_handle));              
2398
2399                 // get the # of samples we'll average for one line
2400                 avg_len = (int)((float)OM_VOX_RECORD_INT * ((1024.0f * 11.0f) / 1000.0f)) / c_width;                            
2401
2402                 // blit the waveform
2403                 gr_set_color_fast(&Color_red);          
2404                 for(idx=0; idx < c_width; idx++){
2405                         // reset the running average
2406                         running_avg = 0;
2407                         for(a_idx = 0; a_idx < avg_len; a_idx++){
2408                                 if(buf_offset < (OM_VOX_COMP_SIZE - 2)){
2409                                         running_avg += (int)Om_vox_comp_buffer[buf_offset] - 128;                       
2410
2411                                         // increment the buffer offset                          
2412                                         buf_offset++;
2413                                 }
2414                         }
2415
2416                         running_avg /= avg_len;                 
2417                         gr_line((gr_screen.max_w - OM_VOX_WAVE_WIDTH)/2 + idx, OM_VOX_WAVE_Y, (gr_screen.max_w - OM_VOX_WAVE_WIDTH)/2 + idx, OM_VOX_WAVE_Y + running_avg);
2418                 }                               
2419                 break;
2420         }
2421 }
2422
2423 // process/display the player list
2424 void options_multi_vox_process_player_list()
2425 {
2426         int idx;
2427         int y_start,p_count;
2428         int selected_index,click_y;
2429         char str[CALLSIGN_LEN+2];
2430
2431         // check for mouse clicks
2432         if(Om_vox_plist_button.pressed()){
2433                 Om_vox_plist_button.get_mouse_pos(NULL,&click_y);
2434                 selected_index = (click_y / 10) + Om_vox_plist_start;
2435
2436                 // if he clicked on a valid player, select him
2437                 if(Om_vox_players[selected_index] != NULL){
2438                         Om_vox_player_select = Om_vox_players[selected_index];
2439
2440                         nprintf(("Network","Selecting player %s\n",Om_vox_player_select->player->callsign));
2441                 }
2442         }
2443
2444         // draw the list of players
2445         p_count = 0;
2446         y_start = Om_vox_plist_coords[gr_screen.res][1];
2447         for(idx = Om_vox_plist_start; idx < Om_vox_num_players; idx++){
2448                 if(Om_vox_players[idx] != NULL){
2449                         // if he's the selected player, highlight him
2450                         if(Om_vox_players[idx] == Om_vox_player_select){
2451                                 gr_set_color_fast(&Color_bright);
2452                         } else {
2453                                 gr_set_color_fast(&Color_normal);
2454                         }
2455
2456                         // force fit his callsign
2457                         strcpy(str,Om_vox_players[idx]->player->callsign);
2458                         gr_force_fit_string(str, CALLSIGN_LEN+1, Om_vox_plist_coords[gr_screen.res][2]);
2459
2460                         // blit the callsign
2461                         gr_string(Om_vox_plist_coords[gr_screen.res][0], y_start, str);
2462
2463                         // increment the y index
2464                         y_start += 10;
2465
2466                         // increment the player count
2467                         p_count++;
2468                 }
2469
2470                 // if we've reached max display, break out
2471                 if(p_count >= Om_vox_plist_max_display[gr_screen.res]){
2472                         break;
2473                 }
2474         }
2475 }       
2476
2477 // get the index into the player list of the passed netplayer
2478 int options_multi_vox_plist_get(net_player *pl)
2479 {
2480         int idx;
2481
2482         for(idx=0;idx<Om_vox_num_players;idx++){
2483                 if(pl == Om_vox_players[idx]){
2484                         return idx;
2485                 }
2486         }
2487
2488         // should neve get here. hmmm.
2489         Int3();
2490         return -1;
2491 }
2492
2493 // scroll the player list down
2494 void options_multi_vox_plist_scroll_down()
2495 {
2496         if(Om_vox_num_players < Om_vox_plist_max_display[gr_screen.res]){
2497                 gamesnd_play_iface(SND_GENERAL_FAIL);
2498                 return;
2499         }
2500
2501         if((Om_vox_num_players - Om_vox_plist_start) >= Om_vox_plist_max_display[gr_screen.res]){
2502                 Om_vox_plist_start++;
2503                 gamesnd_play_iface(SND_USER_SELECT);
2504         } else {
2505                 gamesnd_play_iface(SND_GENERAL_FAIL);
2506         }
2507 }
2508
2509 // scroll the player list up
2510 void options_multi_vox_plist_scroll_up()
2511 {
2512         if(Om_vox_plist_start > 0){
2513                 Om_vox_plist_start--;
2514                 gamesnd_play_iface(SND_USER_SELECT);
2515         } else {
2516                 gamesnd_play_iface(SND_GENERAL_FAIL);
2517         }
2518 }
2519
2520
2521 // extern functions -----------------------------------------------------
2522
2523 // called when the options screen is initialized, pass in the UI window
2524 void options_multi_init(UI_WINDOW *options_window)
2525 {
2526         // assign the options window
2527         Om_window = options_window;
2528
2529         // load the background bitmaps
2530         options_multi_load_bmaps();     
2531
2532         // load the controls for the protocol area
2533         options_multi_load_protocol_controls();
2534
2535         // load the controls for the general tab
2536         options_multi_load_gen_controls();
2537
2538         // load the controls for the voice tab
2539         options_multi_load_vox_controls();
2540
2541         // disable all the protocol controls
2542         options_multi_disable_protocol_controls();
2543
2544         // disable all the general tab controls
2545         options_multi_disable_gen_controls();
2546
2547         // disable all the voice tab controls
2548         options_multi_disable_vox_controls();
2549
2550         // intialize the protocol section vars
2551         options_multi_init_protocol_vars();
2552
2553         // initialize the general tab vars
2554         options_multi_init_gen_vars();
2555
2556         // initialize the voice tab vars
2557         options_multi_init_vox_vars();
2558
2559         // intialize the multiplayer voice recording system
2560         if( !((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_CONNECTED)) ){
2561                 multi_voice_init();
2562         }
2563
2564         // set the default screen mode
2565         Om_mode = OM_MODE_NONE;
2566 }
2567
2568 // do frame for the multi options screen
2569 void options_multi_do(int key)
2570 {               
2571         // do frame for the protocol section
2572         options_multi_protocol_do(key);
2573
2574         // process and blit any notification messages
2575         options_multi_notify_process();
2576
2577         // process the proper tab control
2578         switch(Om_mode){
2579         case OM_MODE_GENERAL:
2580                 options_multi_gen_do();
2581                 break;
2582         case OM_MODE_VOX:
2583                 options_multi_vox_do();
2584                 break;
2585         default :
2586                 Int3();         
2587         }       
2588 }
2589
2590 // called when the entire options screen is closed
2591 void options_multi_close()
2592 {
2593         // null out the window handle
2594         Om_window = NULL;
2595
2596         // unload all background bitmaps
2597         options_multi_unload_bmaps();
2598
2599         // stop any playing voice
2600         rtvoice_stop_playback_all();
2601
2602         // unset the screen mode
2603         Om_mode = OM_MODE_NONE;
2604 }
2605
2606 // called if the accept button on the main options screen was hit
2607 void options_multi_accept()
2608 {       
2609         // accept function for the protocol section
2610         options_multi_protocol_accept();
2611
2612         // accept function for the general tab
2613         options_multi_gen_accept();
2614
2615         // accept function for the voice tab
2616         options_multi_vox_accept();
2617
2618         // if Net_player is not null, copy these new settings to him
2619         if(Net_player != NULL){
2620                 multi_options_local_load(&Net_player->p_info.options, NULL);            
2621         }
2622         multi_options_local_load(&Player->m_local_options, NULL);
2623
2624         // if we're connected to a game server, update our options on the server now
2625         if((Net_player != NULL) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && MULTI_CONNECTED(Net_players[MY_NET_PLAYER_NUM]) ){
2626                 multi_options_update_local();
2627         }
2628 }
2629
2630 // called when the multiplayer tab is hit - initializes/switches all necessary data.
2631 // NOTE : this is different from the initialization function, which is called only when the options menu is started
2632 void options_multi_select()
2633 {
2634 #ifndef FS1_DEMO
2635         // set the windows mask bitmap
2636         Assert(Om_mask_0 >= 0);
2637         Om_window->set_mask_bmap(Om_mask_0, Om_background_0_mask_fname[gr_screen.res]);
2638
2639         // set the default screen mode
2640         Om_mode = OM_MODE_GENERAL;
2641
2642         // clear any notification messages
2643         Om_notify_stamp = -1;   
2644
2645         // enable all the protocol controls
2646         options_multi_enable_protocol_controls();       
2647
2648         // enable the general tab controls
2649         options_multi_enable_gen_controls();
2650 #endif
2651 }
2652
2653 // return the bitmap handle of the current background bitmap, or -1 if the multiplayer tab is not active
2654 int options_multi_background_bitmap()
2655 {
2656 #ifndef FS1_DEMO
2657         // return the background bitmap mode based upon the current mode
2658         switch(Om_mode){
2659         case OM_MODE_GENERAL:
2660                 return Om_background_0;
2661
2662         case OM_MODE_VOX:
2663                 return Om_background_1;
2664         }
2665
2666         // unknown mode of some kind
2667         return -1;
2668 #endif
2669 }
2670
2671 // called when the multiplayer tab has been switched from
2672 void options_multi_unselect()
2673 {
2674         // unset the mode
2675         Om_mode = OM_MODE_NONE;
2676
2677         // disable all the protocol controls
2678         options_multi_disable_protocol_controls();
2679
2680         // disable all the general tab controls
2681         options_multi_disable_gen_controls();
2682
2683         // disable all the vox tab controls
2684         options_multi_disable_vox_controls();
2685
2686         // stop any test voice recording
2687         multi_voice_test_record_stop();
2688 }
2689
2690 // set voice sound buffer for display 
2691 void options_multi_set_voice_data(unsigned char *sound_buf,int buf_size,unsigned char *comp_buf, int comp_size, int uncomp_size, double gain)
2692 {
2693         // copy the buffer to the vox tab data
2694         if(buf_size > OM_VOX_BUF_SIZE){
2695                 memcpy(Om_vox_voice_buffer,sound_buf,OM_VOX_BUF_SIZE);
2696                 Om_vox_voice_buffer_size = OM_VOX_BUF_SIZE;
2697         } else {
2698                 memcpy(Om_vox_voice_buffer,sound_buf,buf_size);
2699                 Om_vox_voice_buffer_size = buf_size;
2700         }
2701
2702         // copy and uncompress the compressed buffer
2703         if(Om_vox_voice_comp_size == -1){
2704                 Om_vox_voice_comp_size = 0;
2705         }
2706         // if we can fit it, decompress this data
2707         if((Om_vox_voice_comp_size + uncomp_size) < OM_VOX_COMP_SIZE){
2708                 // uncompress the data
2709                 rtvoice_uncompress(comp_buf, comp_size, gain, Om_vox_comp_buffer + Om_vox_voice_comp_size, uncomp_size);
2710
2711                 Om_vox_voice_comp_size += uncomp_size;
2712         }
2713 }
2714
2715 // return whether we want to eat a tabbed keypress
2716 int options_multi_eat_tab()
2717 {
2718         // do we want to eat the tab key or not
2719         if(Om_tracker_passwd.has_focus() || Om_tracker_login.has_focus() || Om_tracker_squad_name.has_focus()){
2720                 return 1;
2721         }
2722
2723         return 0;
2724 }
2725