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