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