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