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