1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2000 by DooM Legacy Team.
4 // Copyright (C) 1999-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file  g_input.c
11 /// \brief handle mouse/keyboard/joystick inputs,
12 ///        maps inputs to game controls (forward, spin, jump...)
13 
14 #include "doomdef.h"
15 #include "doomstat.h"
16 #include "g_input.h"
17 #include "keys.h"
18 #include "hu_stuff.h" // need HUFONT start & end
19 #include "d_net.h"
20 #include "console.h"
21 
22 #define MAXMOUSESENSITIVITY 100 // sensitivity steps
23 
24 static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY, "MAX"}, {0, NULL}};
25 static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}};
26 
27 // mouse values are used once
28 consvar_t cv_mousesens = CVAR_INIT ("mousesens", "20", CV_SAVE, mousesens_cons_t, NULL);
29 consvar_t cv_mousesens2 = CVAR_INIT ("mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL);
30 consvar_t cv_mouseysens = CVAR_INIT ("mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL);
31 consvar_t cv_mouseysens2 = CVAR_INIT ("mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL);
32 consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL);
33 
34 INT32 mousex, mousey;
35 INT32 mlooky; // like mousey but with a custom sensitivity for mlook
36 
37 INT32 mouse2x, mouse2y, mlook2y;
38 
39 // joystick values are repeated
40 INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET];
41 
42 // current state of the keys: true if pushed
43 UINT8 gamekeydown[NUMINPUTS];
44 
45 // two key codes (or virtual key) per game control
46 INT32 gamecontrol[num_gamecontrols][2];
47 INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player
48 INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention
49 INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2];
50 
51 // lists of GC codes for selective operation
52 const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = {
53 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
54 	gc_turnleft, gc_turnright
55 };
56 
57 const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = {
58 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
59 	gc_turnleft, gc_turnright,
60 	gc_jump, gc_spin
61 };
62 
63 const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = {
64 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
65 	gc_lookup, gc_lookdown, gc_turnleft, gc_turnright, gc_centerview,
66 	gc_jump, gc_spin,
67 	gc_fire, gc_firenormal
68 };
69 
70 const INT32 gcl_movement[num_gcl_movement] = {
71 	gc_forward, gc_backward, gc_strafeleft, gc_straferight
72 };
73 
74 const INT32 gcl_camera[num_gcl_camera] = {
75 	gc_turnleft, gc_turnright
76 };
77 
78 const INT32 gcl_movement_camera[num_gcl_movement_camera] = {
79 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
80 	gc_turnleft, gc_turnright
81 };
82 
83 const INT32 gcl_jump[num_gcl_jump] = { gc_jump };
84 
85 const INT32 gcl_spin[num_gcl_spin] = { gc_spin };
86 
87 const INT32 gcl_jump_spin[num_gcl_jump_spin] = {
88 	gc_jump, gc_spin
89 };
90 
91 typedef struct
92 {
93 	UINT8 time;
94 	UINT8 state;
95 	UINT8 clicks;
96 } dclick_t;
97 static dclick_t mousedclicks[MOUSEBUTTONS];
98 static dclick_t joydclicks[JOYBUTTONS + JOYHATS*4];
99 static dclick_t mouse2dclicks[MOUSEBUTTONS];
100 static dclick_t joy2dclicks[JOYBUTTONS + JOYHATS*4];
101 
102 // protos
103 static UINT8 G_CheckDoubleClick(UINT8 state, dclick_t *dt);
104 
105 //
106 // Remaps the inputs to game controls.
107 //
108 // A game control can be triggered by one or more keys/buttons.
109 //
110 // Each key/mousebutton/joybutton triggers ONLY ONE game control.
111 //
G_MapEventsToControls(event_t * ev)112 void G_MapEventsToControls(event_t *ev)
113 {
114 	INT32 i;
115 	UINT8 flag;
116 
117 	switch (ev->type)
118 	{
119 		case ev_keydown:
120 			if (ev->data1 < NUMINPUTS)
121 				gamekeydown[ev->data1] = 1;
122 #ifdef PARANOIA
123 			else
124 			{
125 				CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->data1);
126 			}
127 
128 #endif
129 			break;
130 
131 		case ev_keyup:
132 			if (ev->data1 < NUMINPUTS)
133 				gamekeydown[ev->data1] = 0;
134 #ifdef PARANOIA
135 			else
136 			{
137 				CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->data1);
138 			}
139 #endif
140 			break;
141 
142 		case ev_mouse: // buttons are virtual keys
143 			if (menuactive || CON_Ready() || chat_on)
144 				break;
145 			mousex = (INT32)(ev->data2*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f));
146 			mousey = (INT32)(ev->data3*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f));
147 			mlooky = (INT32)(ev->data3*((cv_mouseysens.value*cv_mousesens.value)/110.0f + 0.1f));
148 			break;
149 
150 		case ev_joystick: // buttons are virtual keys
151 			i = ev->data1;
152 			if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on)
153 				break;
154 			if (ev->data2 != INT32_MAX) joyxmove[i] = ev->data2;
155 			if (ev->data3 != INT32_MAX) joyymove[i] = ev->data3;
156 			break;
157 
158 		case ev_joystick2: // buttons are virtual keys
159 			i = ev->data1;
160 			if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on)
161 				break;
162 			if (ev->data2 != INT32_MAX) joy2xmove[i] = ev->data2;
163 			if (ev->data3 != INT32_MAX) joy2ymove[i] = ev->data3;
164 			break;
165 
166 		case ev_mouse2: // buttons are virtual keys
167 			if (menuactive || CON_Ready() || chat_on)
168 				break;
169 			mouse2x = (INT32)(ev->data2*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f));
170 			mouse2y = (INT32)(ev->data3*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f));
171 			mlook2y = (INT32)(ev->data3*((cv_mouseysens2.value*cv_mousesens2.value)/110.0f + 0.1f));
172 			break;
173 
174 		default:
175 			break;
176 	}
177 
178 	// ALWAYS check for mouse & joystick double-clicks even if no mouse event
179 	for (i = 0; i < MOUSEBUTTONS; i++)
180 	{
181 		flag = G_CheckDoubleClick(gamekeydown[KEY_MOUSE1+i], &mousedclicks[i]);
182 		gamekeydown[KEY_DBLMOUSE1+i] = flag;
183 	}
184 
185 	for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++)
186 	{
187 		flag = G_CheckDoubleClick(gamekeydown[KEY_JOY1+i], &joydclicks[i]);
188 		gamekeydown[KEY_DBLJOY1+i] = flag;
189 	}
190 
191 	for (i = 0; i < MOUSEBUTTONS; i++)
192 	{
193 		flag = G_CheckDoubleClick(gamekeydown[KEY_2MOUSE1+i], &mouse2dclicks[i]);
194 		gamekeydown[KEY_DBL2MOUSE1+i] = flag;
195 	}
196 
197 	for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++)
198 	{
199 		flag = G_CheckDoubleClick(gamekeydown[KEY_2JOY1+i], &joy2dclicks[i]);
200 		gamekeydown[KEY_DBL2JOY1+i] = flag;
201 	}
202 }
203 
204 //
205 // General double-click detection routine for any kind of input.
206 //
G_CheckDoubleClick(UINT8 state,dclick_t * dt)207 static UINT8 G_CheckDoubleClick(UINT8 state, dclick_t *dt)
208 {
209 	if (state != dt->state && dt->time > 1)
210 	{
211 		dt->state = state;
212 		if (state)
213 			dt->clicks++;
214 		if (dt->clicks == 2)
215 		{
216 			dt->clicks = 0;
217 			return true;
218 		}
219 		else
220 			dt->time = 0;
221 	}
222 	else
223 	{
224 		dt->time++;
225 		if (dt->time > 20)
226 		{
227 			dt->clicks = 0;
228 			dt->state = 0;
229 		}
230 	}
231 	return false;
232 }
233 
234 typedef struct
235 {
236 	INT32 keynum;
237 	const char *name;
238 } keyname_t;
239 
240 static keyname_t keynames[] =
241 {
242 	{KEY_SPACE, "SPACE"},
243 	{KEY_CAPSLOCK, "CAPS LOCK"},
244 	{KEY_ENTER, "ENTER"},
245 	{KEY_TAB, "TAB"},
246 	{KEY_ESCAPE, "ESCAPE"},
247 	{KEY_BACKSPACE, "BACKSPACE"},
248 
249 	{KEY_NUMLOCK, "NUMLOCK"},
250 	{KEY_SCROLLLOCK, "SCROLLLOCK"},
251 
252 	// bill gates keys
253 	{KEY_LEFTWIN, "LEFTWIN"},
254 	{KEY_RIGHTWIN, "RIGHTWIN"},
255 	{KEY_MENU, "MENU"},
256 
257 	{KEY_LSHIFT, "LSHIFT"},
258 	{KEY_RSHIFT, "RSHIFT"},
259 	{KEY_LSHIFT, "SHIFT"},
260 	{KEY_LCTRL, "LCTRL"},
261 	{KEY_RCTRL, "RCTRL"},
262 	{KEY_LCTRL, "CTRL"},
263 	{KEY_LALT, "LALT"},
264 	{KEY_RALT, "RALT"},
265 	{KEY_LALT, "ALT"},
266 
267 	// keypad keys
268 	{KEY_KPADSLASH, "KEYPAD /"},
269 	{KEY_KEYPAD7, "KEYPAD 7"},
270 	{KEY_KEYPAD8, "KEYPAD 8"},
271 	{KEY_KEYPAD9, "KEYPAD 9"},
272 	{KEY_MINUSPAD, "KEYPAD -"},
273 	{KEY_KEYPAD4, "KEYPAD 4"},
274 	{KEY_KEYPAD5, "KEYPAD 5"},
275 	{KEY_KEYPAD6, "KEYPAD 6"},
276 	{KEY_PLUSPAD, "KEYPAD +"},
277 	{KEY_KEYPAD1, "KEYPAD 1"},
278 	{KEY_KEYPAD2, "KEYPAD 2"},
279 	{KEY_KEYPAD3, "KEYPAD 3"},
280 	{KEY_KEYPAD0, "KEYPAD 0"},
281 	{KEY_KPADDEL, "KEYPAD ."},
282 
283 	// extended keys (not keypad)
284 	{KEY_HOME, "HOME"},
285 	{KEY_UPARROW, "UP ARROW"},
286 	{KEY_PGUP, "PGUP"},
287 	{KEY_LEFTARROW, "LEFT ARROW"},
288 	{KEY_RIGHTARROW, "RIGHT ARROW"},
289 	{KEY_END, "END"},
290 	{KEY_DOWNARROW, "DOWN ARROW"},
291 	{KEY_PGDN, "PGDN"},
292 	{KEY_INS, "INS"},
293 	{KEY_DEL, "DEL"},
294 
295 	// other keys
296 	{KEY_F1, "F1"},
297 	{KEY_F2, "F2"},
298 	{KEY_F3, "F3"},
299 	{KEY_F4, "F4"},
300 	{KEY_F5, "F5"},
301 	{KEY_F6, "F6"},
302 	{KEY_F7, "F7"},
303 	{KEY_F8, "F8"},
304 	{KEY_F9, "F9"},
305 	{KEY_F10, "F10"},
306 	{KEY_F11, "F11"},
307 	{KEY_F12, "F12"},
308 
309 	// KEY_CONSOLE has an exception in the keyname code
310 	{'`', "TILDE"},
311 	{KEY_PAUSE, "PAUSE/BREAK"},
312 
313 	// virtual keys for mouse buttons and joystick buttons
314 	{KEY_MOUSE1+0,"MOUSE1"},
315 	{KEY_MOUSE1+1,"MOUSE2"},
316 	{KEY_MOUSE1+2,"MOUSE3"},
317 	{KEY_MOUSE1+3,"MOUSE4"},
318 	{KEY_MOUSE1+4,"MOUSE5"},
319 	{KEY_MOUSE1+5,"MOUSE6"},
320 	{KEY_MOUSE1+6,"MOUSE7"},
321 	{KEY_MOUSE1+7,"MOUSE8"},
322 	{KEY_2MOUSE1+0,"SEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2
323 	{KEY_2MOUSE1+1,"SEC_MOUSE1"},
324 	{KEY_2MOUSE1+2,"SEC_MOUSE3"},
325 	{KEY_2MOUSE1+3,"SEC_MOUSE4"},
326 	{KEY_2MOUSE1+4,"SEC_MOUSE5"},
327 	{KEY_2MOUSE1+5,"SEC_MOUSE6"},
328 	{KEY_2MOUSE1+6,"SEC_MOUSE7"},
329 	{KEY_2MOUSE1+7,"SEC_MOUSE8"},
330 	{KEY_MOUSEWHEELUP, "Wheel 1 UP"},
331 	{KEY_MOUSEWHEELDOWN, "Wheel 1 Down"},
332 	{KEY_2MOUSEWHEELUP, "Wheel 2 UP"},
333 	{KEY_2MOUSEWHEELDOWN, "Wheel 2 Down"},
334 
335 	{KEY_JOY1+0, "JOY1"},
336 	{KEY_JOY1+1, "JOY2"},
337 	{KEY_JOY1+2, "JOY3"},
338 	{KEY_JOY1+3, "JOY4"},
339 	{KEY_JOY1+4, "JOY5"},
340 	{KEY_JOY1+5, "JOY6"},
341 	{KEY_JOY1+6, "JOY7"},
342 	{KEY_JOY1+7, "JOY8"},
343 	{KEY_JOY1+8, "JOY9"},
344 #if !defined (NOMOREJOYBTN_1S)
345 	// we use up to 32 buttons in DirectInput
346 	{KEY_JOY1+9, "JOY10"},
347 	{KEY_JOY1+10, "JOY11"},
348 	{KEY_JOY1+11, "JOY12"},
349 	{KEY_JOY1+12, "JOY13"},
350 	{KEY_JOY1+13, "JOY14"},
351 	{KEY_JOY1+14, "JOY15"},
352 	{KEY_JOY1+15, "JOY16"},
353 	{KEY_JOY1+16, "JOY17"},
354 	{KEY_JOY1+17, "JOY18"},
355 	{KEY_JOY1+18, "JOY19"},
356 	{KEY_JOY1+19, "JOY20"},
357 	{KEY_JOY1+20, "JOY21"},
358 	{KEY_JOY1+21, "JOY22"},
359 	{KEY_JOY1+22, "JOY23"},
360 	{KEY_JOY1+23, "JOY24"},
361 	{KEY_JOY1+24, "JOY25"},
362 	{KEY_JOY1+25, "JOY26"},
363 	{KEY_JOY1+26, "JOY27"},
364 	{KEY_JOY1+27, "JOY28"},
365 	{KEY_JOY1+28, "JOY29"},
366 	{KEY_JOY1+29, "JOY30"},
367 	{KEY_JOY1+30, "JOY31"},
368 	{KEY_JOY1+31, "JOY32"},
369 #endif
370 	// the DOS version uses Allegro's joystick support
371 	{KEY_HAT1+0, "HATUP"},
372 	{KEY_HAT1+1, "HATDOWN"},
373 	{KEY_HAT1+2, "HATLEFT"},
374 	{KEY_HAT1+3, "HATRIGHT"},
375 	{KEY_HAT1+4, "HATUP2"},
376 	{KEY_HAT1+5, "HATDOWN2"},
377 	{KEY_HAT1+6, "HATLEFT2"},
378 	{KEY_HAT1+7, "HATRIGHT2"},
379 	{KEY_HAT1+8, "HATUP3"},
380 	{KEY_HAT1+9, "HATDOWN3"},
381 	{KEY_HAT1+10, "HATLEFT3"},
382 	{KEY_HAT1+11, "HATRIGHT3"},
383 	{KEY_HAT1+12, "HATUP4"},
384 	{KEY_HAT1+13, "HATDOWN4"},
385 	{KEY_HAT1+14, "HATLEFT4"},
386 	{KEY_HAT1+15, "HATRIGHT4"},
387 
388 	{KEY_DBLMOUSE1+0, "DBLMOUSE1"},
389 	{KEY_DBLMOUSE1+1, "DBLMOUSE2"},
390 	{KEY_DBLMOUSE1+2, "DBLMOUSE3"},
391 	{KEY_DBLMOUSE1+3, "DBLMOUSE4"},
392 	{KEY_DBLMOUSE1+4, "DBLMOUSE5"},
393 	{KEY_DBLMOUSE1+5, "DBLMOUSE6"},
394 	{KEY_DBLMOUSE1+6, "DBLMOUSE7"},
395 	{KEY_DBLMOUSE1+7, "DBLMOUSE8"},
396 	{KEY_DBL2MOUSE1+0, "DBLSEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2
397 	{KEY_DBL2MOUSE1+1, "DBLSEC_MOUSE1"},
398 	{KEY_DBL2MOUSE1+2, "DBLSEC_MOUSE3"},
399 	{KEY_DBL2MOUSE1+3, "DBLSEC_MOUSE4"},
400 	{KEY_DBL2MOUSE1+4, "DBLSEC_MOUSE5"},
401 	{KEY_DBL2MOUSE1+5, "DBLSEC_MOUSE6"},
402 	{KEY_DBL2MOUSE1+6, "DBLSEC_MOUSE7"},
403 	{KEY_DBL2MOUSE1+7, "DBLSEC_MOUSE8"},
404 
405 	{KEY_DBLJOY1+0, "DBLJOY1"},
406 	{KEY_DBLJOY1+1, "DBLJOY2"},
407 	{KEY_DBLJOY1+2, "DBLJOY3"},
408 	{KEY_DBLJOY1+3, "DBLJOY4"},
409 	{KEY_DBLJOY1+4, "DBLJOY5"},
410 	{KEY_DBLJOY1+5, "DBLJOY6"},
411 	{KEY_DBLJOY1+6, "DBLJOY7"},
412 	{KEY_DBLJOY1+7, "DBLJOY8"},
413 #if !defined (NOMOREJOYBTN_1DBL)
414 	{KEY_DBLJOY1+8, "DBLJOY9"},
415 	{KEY_DBLJOY1+9, "DBLJOY10"},
416 	{KEY_DBLJOY1+10, "DBLJOY11"},
417 	{KEY_DBLJOY1+11, "DBLJOY12"},
418 	{KEY_DBLJOY1+12, "DBLJOY13"},
419 	{KEY_DBLJOY1+13, "DBLJOY14"},
420 	{KEY_DBLJOY1+14, "DBLJOY15"},
421 	{KEY_DBLJOY1+15, "DBLJOY16"},
422 	{KEY_DBLJOY1+16, "DBLJOY17"},
423 	{KEY_DBLJOY1+17, "DBLJOY18"},
424 	{KEY_DBLJOY1+18, "DBLJOY19"},
425 	{KEY_DBLJOY1+19, "DBLJOY20"},
426 	{KEY_DBLJOY1+20, "DBLJOY21"},
427 	{KEY_DBLJOY1+21, "DBLJOY22"},
428 	{KEY_DBLJOY1+22, "DBLJOY23"},
429 	{KEY_DBLJOY1+23, "DBLJOY24"},
430 	{KEY_DBLJOY1+24, "DBLJOY25"},
431 	{KEY_DBLJOY1+25, "DBLJOY26"},
432 	{KEY_DBLJOY1+26, "DBLJOY27"},
433 	{KEY_DBLJOY1+27, "DBLJOY28"},
434 	{KEY_DBLJOY1+28, "DBLJOY29"},
435 	{KEY_DBLJOY1+29, "DBLJOY30"},
436 	{KEY_DBLJOY1+30, "DBLJOY31"},
437 	{KEY_DBLJOY1+31, "DBLJOY32"},
438 #endif
439 	{KEY_DBLHAT1+0, "DBLHATUP"},
440 	{KEY_DBLHAT1+1, "DBLHATDOWN"},
441 	{KEY_DBLHAT1+2, "DBLHATLEFT"},
442 	{KEY_DBLHAT1+3, "DBLHATRIGHT"},
443 	{KEY_DBLHAT1+4, "DBLHATUP2"},
444 	{KEY_DBLHAT1+5, "DBLHATDOWN2"},
445 	{KEY_DBLHAT1+6, "DBLHATLEFT2"},
446 	{KEY_DBLHAT1+7, "DBLHATRIGHT2"},
447 	{KEY_DBLHAT1+8, "DBLHATUP3"},
448 	{KEY_DBLHAT1+9, "DBLHATDOWN3"},
449 	{KEY_DBLHAT1+10, "DBLHATLEFT3"},
450 	{KEY_DBLHAT1+11, "DBLHATRIGHT3"},
451 	{KEY_DBLHAT1+12, "DBLHATUP4"},
452 	{KEY_DBLHAT1+13, "DBLHATDOWN4"},
453 	{KEY_DBLHAT1+14, "DBLHATLEFT4"},
454 	{KEY_DBLHAT1+15, "DBLHATRIGHT4"},
455 
456 	{KEY_2JOY1+0, "SEC_JOY1"},
457 	{KEY_2JOY1+1, "SEC_JOY2"},
458 	{KEY_2JOY1+2, "SEC_JOY3"},
459 	{KEY_2JOY1+3, "SEC_JOY4"},
460 	{KEY_2JOY1+4, "SEC_JOY5"},
461 	{KEY_2JOY1+5, "SEC_JOY6"},
462 	{KEY_2JOY1+6, "SEC_JOY7"},
463 	{KEY_2JOY1+7, "SEC_JOY8"},
464 #if !defined (NOMOREJOYBTN_2S)
465 	// we use up to 32 buttons in DirectInput
466 	{KEY_2JOY1+8, "SEC_JOY9"},
467 	{KEY_2JOY1+9, "SEC_JOY10"},
468 	{KEY_2JOY1+10, "SEC_JOY11"},
469 	{KEY_2JOY1+11, "SEC_JOY12"},
470 	{KEY_2JOY1+12, "SEC_JOY13"},
471 	{KEY_2JOY1+13, "SEC_JOY14"},
472 	{KEY_2JOY1+14, "SEC_JOY15"},
473 	{KEY_2JOY1+15, "SEC_JOY16"},
474 	{KEY_2JOY1+16, "SEC_JOY17"},
475 	{KEY_2JOY1+17, "SEC_JOY18"},
476 	{KEY_2JOY1+18, "SEC_JOY19"},
477 	{KEY_2JOY1+19, "SEC_JOY20"},
478 	{KEY_2JOY1+20, "SEC_JOY21"},
479 	{KEY_2JOY1+21, "SEC_JOY22"},
480 	{KEY_2JOY1+22, "SEC_JOY23"},
481 	{KEY_2JOY1+23, "SEC_JOY24"},
482 	{KEY_2JOY1+24, "SEC_JOY25"},
483 	{KEY_2JOY1+25, "SEC_JOY26"},
484 	{KEY_2JOY1+26, "SEC_JOY27"},
485 	{KEY_2JOY1+27, "SEC_JOY28"},
486 	{KEY_2JOY1+28, "SEC_JOY29"},
487 	{KEY_2JOY1+29, "SEC_JOY30"},
488 	{KEY_2JOY1+30, "SEC_JOY31"},
489 	{KEY_2JOY1+31, "SEC_JOY32"},
490 #endif
491 	// the DOS version uses Allegro's joystick support
492 	{KEY_2HAT1+0,  "SEC_HATUP"},
493 	{KEY_2HAT1+1,  "SEC_HATDOWN"},
494 	{KEY_2HAT1+2,  "SEC_HATLEFT"},
495 	{KEY_2HAT1+3,  "SEC_HATRIGHT"},
496 	{KEY_2HAT1+4, "SEC_HATUP2"},
497 	{KEY_2HAT1+5, "SEC_HATDOWN2"},
498 	{KEY_2HAT1+6, "SEC_HATLEFT2"},
499 	{KEY_2HAT1+7, "SEC_HATRIGHT2"},
500 	{KEY_2HAT1+8, "SEC_HATUP3"},
501 	{KEY_2HAT1+9, "SEC_HATDOWN3"},
502 	{KEY_2HAT1+10, "SEC_HATLEFT3"},
503 	{KEY_2HAT1+11, "SEC_HATRIGHT3"},
504 	{KEY_2HAT1+12, "SEC_HATUP4"},
505 	{KEY_2HAT1+13, "SEC_HATDOWN4"},
506 	{KEY_2HAT1+14, "SEC_HATLEFT4"},
507 	{KEY_2HAT1+15, "SEC_HATRIGHT4"},
508 
509 	{KEY_DBL2JOY1+0, "DBLSEC_JOY1"},
510 	{KEY_DBL2JOY1+1, "DBLSEC_JOY2"},
511 	{KEY_DBL2JOY1+2, "DBLSEC_JOY3"},
512 	{KEY_DBL2JOY1+3, "DBLSEC_JOY4"},
513 	{KEY_DBL2JOY1+4, "DBLSEC_JOY5"},
514 	{KEY_DBL2JOY1+5, "DBLSEC_JOY6"},
515 	{KEY_DBL2JOY1+6, "DBLSEC_JOY7"},
516 	{KEY_DBL2JOY1+7, "DBLSEC_JOY8"},
517 #if !defined (NOMOREJOYBTN_2DBL)
518 	{KEY_DBL2JOY1+8, "DBLSEC_JOY9"},
519 	{KEY_DBL2JOY1+9, "DBLSEC_JOY10"},
520 	{KEY_DBL2JOY1+10, "DBLSEC_JOY11"},
521 	{KEY_DBL2JOY1+11, "DBLSEC_JOY12"},
522 	{KEY_DBL2JOY1+12, "DBLSEC_JOY13"},
523 	{KEY_DBL2JOY1+13, "DBLSEC_JOY14"},
524 	{KEY_DBL2JOY1+14, "DBLSEC_JOY15"},
525 	{KEY_DBL2JOY1+15, "DBLSEC_JOY16"},
526 	{KEY_DBL2JOY1+16, "DBLSEC_JOY17"},
527 	{KEY_DBL2JOY1+17, "DBLSEC_JOY18"},
528 	{KEY_DBL2JOY1+18, "DBLSEC_JOY19"},
529 	{KEY_DBL2JOY1+19, "DBLSEC_JOY20"},
530 	{KEY_DBL2JOY1+20, "DBLSEC_JOY21"},
531 	{KEY_DBL2JOY1+21, "DBLSEC_JOY22"},
532 	{KEY_DBL2JOY1+22, "DBLSEC_JOY23"},
533 	{KEY_DBL2JOY1+23, "DBLSEC_JOY24"},
534 	{KEY_DBL2JOY1+24, "DBLSEC_JOY25"},
535 	{KEY_DBL2JOY1+25, "DBLSEC_JOY26"},
536 	{KEY_DBL2JOY1+26, "DBLSEC_JOY27"},
537 	{KEY_DBL2JOY1+27, "DBLSEC_JOY28"},
538 	{KEY_DBL2JOY1+28, "DBLSEC_JOY29"},
539 	{KEY_DBL2JOY1+29, "DBLSEC_JOY30"},
540 	{KEY_DBL2JOY1+30, "DBLSEC_JOY31"},
541 	{KEY_DBL2JOY1+31, "DBLSEC_JOY32"},
542 #endif
543 	{KEY_DBL2HAT1+0, "DBLSEC_HATUP"},
544 	{KEY_DBL2HAT1+1, "DBLSEC_HATDOWN"},
545 	{KEY_DBL2HAT1+2, "DBLSEC_HATLEFT"},
546 	{KEY_DBL2HAT1+3, "DBLSEC_HATRIGHT"},
547 	{KEY_DBL2HAT1+4, "DBLSEC_HATUP2"},
548 	{KEY_DBL2HAT1+5, "DBLSEC_HATDOWN2"},
549 	{KEY_DBL2HAT1+6, "DBLSEC_HATLEFT2"},
550 	{KEY_DBL2HAT1+7, "DBLSEC_HATRIGHT2"},
551 	{KEY_DBL2HAT1+8, "DBLSEC_HATUP3"},
552 	{KEY_DBL2HAT1+9, "DBLSEC_HATDOWN3"},
553 	{KEY_DBL2HAT1+10, "DBLSEC_HATLEFT3"},
554 	{KEY_DBL2HAT1+11, "DBLSEC_HATRIGHT3"},
555 	{KEY_DBL2HAT1+12, "DBLSEC_HATUP4"},
556 	{KEY_DBL2HAT1+13, "DBLSEC_HATDOWN4"},
557 	{KEY_DBL2HAT1+14, "DBLSEC_HATLEFT4"},
558 	{KEY_DBL2HAT1+15, "DBLSEC_HATRIGHT4"},
559 
560 };
561 
562 static const char *gamecontrolname[num_gamecontrols] =
563 {
564 	"nothing", // a key/button mapped to gc_null has no effect
565 	"forward",
566 	"backward",
567 	"strafeleft",
568 	"straferight",
569 	"turnleft",
570 	"turnright",
571 	"weaponnext",
572 	"weaponprev",
573 	"weapon1",
574 	"weapon2",
575 	"weapon3",
576 	"weapon4",
577 	"weapon5",
578 	"weapon6",
579 	"weapon7",
580 	"weapon8",
581 	"weapon9",
582 	"weapon10",
583 	"fire",
584 	"firenormal",
585 	"tossflag",
586 	"spin",
587 	"camtoggle",
588 	"camreset",
589 	"lookup",
590 	"lookdown",
591 	"centerview",
592 	"mouseaiming",
593 	"talkkey",
594 	"teamtalkkey",
595 	"scores",
596 	"jump",
597 	"console",
598 	"pause",
599 	"systemmenu",
600 	"screenshot",
601 	"recordgif",
602 	"viewpoint",
603 	"custom1",
604 	"custom2",
605 	"custom3",
606 };
607 
608 #define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t))
609 
610 //
611 // Detach any keys associated to the given game control
612 // - pass the pointer to the gamecontrol table for the player being edited
G_ClearControlKeys(INT32 (* setupcontrols)[2],INT32 control)613 void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control)
614 {
615 	setupcontrols[control][0] = KEY_NULL;
616 	setupcontrols[control][1] = KEY_NULL;
617 }
618 
G_ClearAllControlKeys(void)619 void G_ClearAllControlKeys(void)
620 {
621 	INT32 i;
622 	for (i = 0; i < num_gamecontrols; i++)
623 	{
624 		G_ClearControlKeys(gamecontrol, i);
625 		G_ClearControlKeys(gamecontrolbis, i);
626 	}
627 }
628 
629 //
630 // Returns the name of a key (or virtual key for mouse and joy)
631 // the input value being an keynum
632 //
G_KeynumToString(INT32 keynum)633 const char *G_KeynumToString(INT32 keynum)
634 {
635 	static char keynamestr[8];
636 
637 	UINT32 j;
638 
639 	// return a string with the ascii char if displayable
640 	if (keynum > ' ' && keynum <= 'z' && keynum != KEY_CONSOLE)
641 	{
642 		keynamestr[0] = (char)keynum;
643 		keynamestr[1] = '\0';
644 		return keynamestr;
645 	}
646 
647 	// find a description for special keys
648 	for (j = 0; j < NUMKEYNAMES; j++)
649 		if (keynames[j].keynum == keynum)
650 			return keynames[j].name;
651 
652 	// create a name for unknown keys
653 	sprintf(keynamestr, "KEY%d", keynum);
654 	return keynamestr;
655 }
656 
G_KeyStringtoNum(const char * keystr)657 INT32 G_KeyStringtoNum(const char *keystr)
658 {
659 	UINT32 j;
660 
661 	if (!keystr[1] && keystr[0] > ' ' && keystr[0] <= 'z')
662 		return keystr[0];
663 
664 	if (!strncmp(keystr, "KEY", 3) && keystr[3] >= '0' && keystr[3] <= '9')
665 	{
666 		/* what if we out of range bruh? */
667 		j = atoi(&keystr[3]);
668 		if (j < NUMINPUTS)
669 			return j;
670 		return 0;
671 	}
672 
673 	for (j = 0; j < NUMKEYNAMES; j++)
674 		if (!stricmp(keynames[j].name, keystr))
675 			return keynames[j].keynum;
676 
677 	return 0;
678 }
679 
G_DefineDefaultControls(void)680 void G_DefineDefaultControls(void)
681 {
682 	INT32 i;
683 
684 	// FPS game controls (WASD)
685 	gamecontroldefault[gcs_fps][gc_forward    ][0] = 'w';
686 	gamecontroldefault[gcs_fps][gc_backward   ][0] = 's';
687 	gamecontroldefault[gcs_fps][gc_strafeleft ][0] = 'a';
688 	gamecontroldefault[gcs_fps][gc_straferight][0] = 'd';
689 	gamecontroldefault[gcs_fps][gc_lookup     ][0] = KEY_UPARROW;
690 	gamecontroldefault[gcs_fps][gc_lookdown   ][0] = KEY_DOWNARROW;
691 	gamecontroldefault[gcs_fps][gc_turnleft   ][0] = KEY_LEFTARROW;
692 	gamecontroldefault[gcs_fps][gc_turnright  ][0] = KEY_RIGHTARROW;
693 	gamecontroldefault[gcs_fps][gc_centerview ][0] = KEY_END;
694 	gamecontroldefault[gcs_fps][gc_jump       ][0] = KEY_SPACE;
695 	gamecontroldefault[gcs_fps][gc_spin       ][0] = KEY_LSHIFT;
696 	gamecontroldefault[gcs_fps][gc_fire       ][0] = KEY_RCTRL;
697 	gamecontroldefault[gcs_fps][gc_fire       ][1] = KEY_MOUSE1+0;
698 	gamecontroldefault[gcs_fps][gc_firenormal ][0] = 'c';
699 
700 	// Platform game controls (arrow keys)
701 	gamecontroldefault[gcs_platform][gc_forward    ][0] = KEY_UPARROW;
702 	gamecontroldefault[gcs_platform][gc_backward   ][0] = KEY_DOWNARROW;
703 	gamecontroldefault[gcs_platform][gc_strafeleft ][0] = 'a';
704 	gamecontroldefault[gcs_platform][gc_straferight][0] = 'd';
705 	gamecontroldefault[gcs_platform][gc_lookup     ][0] = KEY_PGUP;
706 	gamecontroldefault[gcs_platform][gc_lookdown   ][0] = KEY_PGDN;
707 	gamecontroldefault[gcs_platform][gc_turnleft   ][0] = KEY_LEFTARROW;
708 	gamecontroldefault[gcs_platform][gc_turnright  ][0] = KEY_RIGHTARROW;
709 	gamecontroldefault[gcs_platform][gc_centerview ][0] = KEY_END;
710 	gamecontroldefault[gcs_platform][gc_jump       ][0] = KEY_SPACE;
711 	gamecontroldefault[gcs_platform][gc_spin       ][0] = KEY_LSHIFT;
712 	gamecontroldefault[gcs_platform][gc_fire       ][0] = 's';
713 	gamecontroldefault[gcs_platform][gc_fire       ][1] = KEY_MOUSE1+0;
714 	gamecontroldefault[gcs_platform][gc_firenormal ][0] = 'w';
715 
716 	for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
717 	{
718 		gamecontroldefault[i][gc_weaponnext ][0] = KEY_MOUSEWHEELUP+0;
719 		gamecontroldefault[i][gc_weaponprev ][0] = KEY_MOUSEWHEELDOWN+0;
720 		gamecontroldefault[i][gc_wepslot1   ][0] = '1';
721 		gamecontroldefault[i][gc_wepslot2   ][0] = '2';
722 		gamecontroldefault[i][gc_wepslot3   ][0] = '3';
723 		gamecontroldefault[i][gc_wepslot4   ][0] = '4';
724 		gamecontroldefault[i][gc_wepslot5   ][0] = '5';
725 		gamecontroldefault[i][gc_wepslot6   ][0] = '6';
726 		gamecontroldefault[i][gc_wepslot7   ][0] = '7';
727 		gamecontroldefault[i][gc_wepslot8   ][0] = '8';
728 		gamecontroldefault[i][gc_wepslot9   ][0] = '9';
729 		gamecontroldefault[i][gc_wepslot10  ][0] = '0';
730 		gamecontroldefault[i][gc_tossflag   ][0] = '\'';
731 		gamecontroldefault[i][gc_camtoggle  ][0] = 'v';
732 		gamecontroldefault[i][gc_camreset   ][0] = 'r';
733 		gamecontroldefault[i][gc_talkkey    ][0] = 't';
734 		gamecontroldefault[i][gc_teamkey    ][0] = 'y';
735 		gamecontroldefault[i][gc_scores     ][0] = KEY_TAB;
736 		gamecontroldefault[i][gc_console    ][0] = KEY_CONSOLE;
737 		gamecontroldefault[i][gc_pause      ][0] = 'p';
738 		gamecontroldefault[i][gc_screenshot ][0] = KEY_F8;
739 		gamecontroldefault[i][gc_recordgif  ][0] = KEY_F9;
740 		gamecontroldefault[i][gc_viewpoint  ][0] = KEY_F12;
741 
742 		// Gamepad controls -- same for both schemes
743 		gamecontroldefault[i][gc_weaponnext ][1] = KEY_JOY1+1; // B
744 		gamecontroldefault[i][gc_weaponprev ][1] = KEY_JOY1+2; // X
745 		gamecontroldefault[i][gc_tossflag   ][1] = KEY_JOY1+0; // A
746 		gamecontroldefault[i][gc_spin       ][1] = KEY_JOY1+4; // LB
747 		gamecontroldefault[i][gc_camtoggle  ][1] = KEY_HAT1+0; // D-Pad Up
748 		gamecontroldefault[i][gc_camreset   ][1] = KEY_JOY1+3; // Y
749 		gamecontroldefault[i][gc_centerview ][1] = KEY_JOY1+9; // Right Stick
750 		gamecontroldefault[i][gc_talkkey    ][1] = KEY_HAT1+2; // D-Pad Left
751 		gamecontroldefault[i][gc_scores     ][1] = KEY_HAT1+3; // D-Pad Right
752 		gamecontroldefault[i][gc_jump       ][1] = KEY_JOY1+5; // RB
753 		gamecontroldefault[i][gc_pause      ][1] = KEY_JOY1+6; // Back
754 		gamecontroldefault[i][gc_screenshot ][1] = KEY_HAT1+1; // D-Pad Down
755 		gamecontroldefault[i][gc_systemmenu ][0] = KEY_JOY1+7; // Start
756 
757 		// Second player controls only have joypad defaults
758 		gamecontrolbisdefault[i][gc_weaponnext][0] = KEY_2JOY1+1; // B
759 		gamecontrolbisdefault[i][gc_weaponprev][0] = KEY_2JOY1+2; // X
760 		gamecontrolbisdefault[i][gc_tossflag  ][0] = KEY_2JOY1+0; // A
761 		gamecontrolbisdefault[i][gc_spin      ][0] = KEY_2JOY1+4; // LB
762 		gamecontrolbisdefault[i][gc_camreset  ][0] = KEY_2JOY1+3; // Y
763 		gamecontrolbisdefault[i][gc_centerview][0] = KEY_2JOY1+9; // Right Stick
764 		gamecontrolbisdefault[i][gc_jump      ][0] = KEY_2JOY1+5; // RB
765 		//gamecontrolbisdefault[i][gc_pause     ][0] = KEY_2JOY1+6; // Back
766 		//gamecontrolbisdefault[i][gc_systemmenu][0] = KEY_2JOY1+7; // Start
767 		gamecontrolbisdefault[i][gc_camtoggle ][0] = KEY_2HAT1+0; // D-Pad Up
768 		gamecontrolbisdefault[i][gc_screenshot][0] = KEY_2HAT1+1; // D-Pad Down
769 		//gamecontrolbisdefault[i][gc_talkkey   ][0] = KEY_2HAT1+2; // D-Pad Left
770 		//gamecontrolbisdefault[i][gc_scores    ][0] = KEY_2HAT1+3; // D-Pad Right
771 	}
772 }
773 
G_GetControlScheme(INT32 (* fromcontrols)[2],const INT32 * gclist,INT32 gclen)774 INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen)
775 {
776 	INT32 i, j, gc;
777 	boolean skipscheme;
778 
779 	for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
780 	{
781 		skipscheme = false;
782 		for (j = 0; j < (gclist && gclen ? gclen : num_gamecontrols); j++)
783 		{
784 			gc = (gclist && gclen) ? gclist[j] : j;
785 			if (((fromcontrols[gc][0] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][0] : true) &&
786 				((fromcontrols[gc][0] && gamecontroldefault[i][gc][1]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][1] : true) &&
787 				((fromcontrols[gc][1] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][1] != gamecontroldefault[i][gc][0] : true) &&
788 				((fromcontrols[gc][1] && gamecontroldefault[i][gc][1]) ? fromcontrols[gc][1] != gamecontroldefault[i][gc][1] : true))
789 			{
790 				skipscheme = true;
791 				break;
792 			}
793 		}
794 		if (!skipscheme)
795 			return i;
796 	}
797 
798 	return gcs_custom;
799 }
800 
G_CopyControls(INT32 (* setupcontrols)[2],INT32 (* fromcontrols)[2],const INT32 * gclist,INT32 gclen)801 void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen)
802 {
803 	INT32 i, gc;
804 
805 	for (i = 0; i < (gclist && gclen ? gclen : num_gamecontrols); i++)
806 	{
807 		gc = (gclist && gclen) ? gclist[i] : i;
808 		setupcontrols[gc][0] = fromcontrols[gc][0];
809 		setupcontrols[gc][1] = fromcontrols[gc][1];
810 	}
811 }
812 
G_SaveKeySetting(FILE * f,INT32 (* fromcontrols)[2],INT32 (* fromcontrolsbis)[2])813 void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2])
814 {
815 	INT32 i;
816 
817 	for (i = 1; i < num_gamecontrols; i++)
818 	{
819 		fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i],
820 			G_KeynumToString(fromcontrols[i][0]));
821 
822 		if (fromcontrols[i][1])
823 			fprintf(f, " \"%s\"\n", G_KeynumToString(fromcontrols[i][1]));
824 		else
825 			fprintf(f, "\n");
826 	}
827 
828 	for (i = 1; i < num_gamecontrols; i++)
829 	{
830 		fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i],
831 			G_KeynumToString(fromcontrolsbis[i][0]));
832 
833 		if (fromcontrolsbis[i][1])
834 			fprintf(f, " \"%s\"\n", G_KeynumToString(fromcontrolsbis[i][1]));
835 		else
836 			fprintf(f, "\n");
837 	}
838 }
839 
G_CheckDoubleUsage(INT32 keynum,boolean modify)840 INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify)
841 {
842 	INT32 result = gc_null;
843 	if (cv_controlperkey.value == 1)
844 	{
845 		INT32 i;
846 		for (i = 0; i < num_gamecontrols; i++)
847 		{
848 			if (gamecontrol[i][0] == keynum)
849 			{
850 				result = i;
851 				if (modify) gamecontrol[i][0] = KEY_NULL;
852 			}
853 			if (gamecontrol[i][1] == keynum)
854 			{
855 				result = i;
856 				if (modify) gamecontrol[i][1] = KEY_NULL;
857 			}
858 			if (gamecontrolbis[i][0] == keynum)
859 			{
860 				result = i;
861 				if (modify) gamecontrolbis[i][0] = KEY_NULL;
862 			}
863 			if (gamecontrolbis[i][1] == keynum)
864 			{
865 				result = i;
866 				if (modify) gamecontrolbis[i][1] = KEY_NULL;
867 			}
868 			if (result && !modify)
869 				return result;
870 		}
871 	}
872 	return result;
873 }
874 
G_FilterKeyByVersion(INT32 numctrl,INT32 keyidx,INT32 player,INT32 * keynum1,INT32 * keynum2,boolean * nestedoverride)875 static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2, boolean *nestedoverride)
876 {
877 	// Special case: ignore KEY_PAUSE because it's hardcoded
878 	if (keyidx == 0 && *keynum1 == KEY_PAUSE)
879 	{
880 		if (*keynum2 != KEY_PAUSE)
881 		{
882 			*keynum1 = *keynum2; // shift down keynum2 and continue
883 			*keynum2 = 0;
884 		}
885 		else
886 			return -1; // skip setting control
887 	}
888 	else if (keyidx == 1 && *keynum2 == KEY_PAUSE)
889 		return -1; // skip setting control
890 
891 	if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22
892 		numctrl == gc_weaponnext || numctrl == gc_weaponprev || numctrl == gc_tossflag ||
893 		numctrl == gc_spin || numctrl == gc_camreset || numctrl == gc_jump ||
894 		numctrl == gc_pause || numctrl == gc_systemmenu || numctrl == gc_camtoggle ||
895 		numctrl == gc_screenshot || numctrl == gc_talkkey || numctrl == gc_scores ||
896 		numctrl == gc_centerview
897 	))
898 	{
899 		INT32 keynum = 0, existingctrl = 0;
900 		INT32 defaultkey;
901 		boolean defaultoverride = false;
902 
903 		// get the default gamecontrol
904 		if (player == 0 && numctrl == gc_systemmenu)
905 			defaultkey = gamecontrol[numctrl][0];
906 		else
907 			defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]);
908 
909 		// Assign joypad button defaults if there is an open slot.
910 		// At this point, gamecontrol/bis should have the default controls
911 		// (unless LOADCONFIG is being run)
912 		//
913 		// If the player runs SETCONTROL in-game, this block should not be reached
914 		// because EXECVERSION is locked onto the latest version.
915 		if (keyidx == 0 && !*keynum1)
916 		{
917 			if (*keynum2) // push keynum2 down; this is an edge case
918 			{
919 				*keynum1 = *keynum2;
920 				*keynum2 = 0;
921 				keynum = *keynum1;
922 			}
923 			else
924 			{
925 				keynum = defaultkey;
926 				defaultoverride = true;
927 			}
928 		}
929 		else if (keyidx == 1 && (!*keynum2 || (!*keynum1 && *keynum2))) // last one is the same edge case as above
930 		{
931 			keynum = defaultkey;
932 			defaultoverride = true;
933 		}
934 		else // default to the specified keynum
935 			keynum = (keyidx == 1 ? *keynum2 : *keynum1);
936 
937 		// Did our last call override keynum2?
938 		if (*nestedoverride)
939 		{
940 			defaultoverride = true;
941 			*nestedoverride = false;
942 		}
943 
944 		// Fill keynum2 with the default control
945 		if (keyidx == 0 && !*keynum2)
946 		{
947 			*keynum2 = defaultkey;
948 			// Tell the next call that this is an override
949 			*nestedoverride = true;
950 
951 			// if keynum2 already matches keynum1, we probably recursed
952 			// so unset it
953 			if (*keynum1 == *keynum2)
954 			{
955 				*keynum2 = 0;
956 				*nestedoverride = false;
957 		}
958 		}
959 
960 		// check if the key is being used somewhere else before passing it
961 		// pass it through if it's the same numctrl. This is an edge case -- when using
962 		// LOADCONFIG, gamecontrol is not reset with default.
963 		//
964 		// Also, only check if we're actually overriding, to preserve behavior where
965 		// config'd keys overwrite default keys.
966 		if (defaultoverride)
967 			existingctrl = G_CheckDoubleUsage(keynum, false);
968 
969 		if (keynum && (!existingctrl || existingctrl == numctrl))
970 			return keynum;
971 		else if (keyidx == 0 && *keynum2)
972 		{
973 			// try it again and push down keynum2
974 			*keynum1 = *keynum2;
975 			*keynum2 = 0;
976 			return G_FilterKeyByVersion(numctrl, keyidx, player, keynum1, keynum2, nestedoverride);
977 			// recursion *should* be safe because we only assign keynum2 to a joy default
978 			// and then clear it if we find that keynum1 already has the joy default.
979 		}
980 		else
981 			return 0;
982 	}
983 
984 	// All's good, so pass the keynum as-is
985 	if (keyidx == 1)
986 		return *keynum2;
987 	else //if (keyidx == 0)
988 		return *keynum1;
989 }
990 
setcontrol(INT32 (* gc)[2])991 static void setcontrol(INT32 (*gc)[2])
992 {
993 	INT32 numctrl;
994 	const char *namectrl;
995 	INT32 keynum, keynum1, keynum2;
996 	INT32 player = ((void*)gc == (void*)&gamecontrolbis ? 1 : 0);
997 	boolean nestedoverride = false;
998 
999 	// Update me for 2.3
1000 	namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin";
1001 
1002 	for (numctrl = 0; numctrl < num_gamecontrols && stricmp(namectrl, gamecontrolname[numctrl]);
1003 		numctrl++)
1004 		;
1005 	if (numctrl == num_gamecontrols)
1006 	{
1007 		CONS_Printf(M_GetText("Control '%s' unknown\n"), namectrl);
1008 		return;
1009 	}
1010 	keynum1 = G_KeyStringtoNum(COM_Argv(2));
1011 	keynum2 = G_KeyStringtoNum(COM_Argv(3));
1012 	keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride);
1013 
1014 	if (keynum >= 0)
1015 	{
1016 		(void)G_CheckDoubleUsage(keynum, true);
1017 
1018 		// if keynum was rejected, try it again with keynum2
1019 		if (!keynum && keynum2)
1020 		{
1021 			keynum1 = keynum2; // push down keynum2
1022 			keynum2 = 0;
1023 			keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride);
1024 			if (keynum >= 0)
1025 				(void)G_CheckDoubleUsage(keynum, true);
1026 		}
1027 	}
1028 
1029 	if (keynum >= 0)
1030 		gc[numctrl][0] = keynum;
1031 
1032 	if (keynum2)
1033 	{
1034 		keynum = G_FilterKeyByVersion(numctrl, 1, player, &keynum1, &keynum2, &nestedoverride);
1035 		if (keynum >= 0)
1036 		{
1037 			if (keynum != gc[numctrl][0])
1038 				gc[numctrl][1] = keynum;
1039 			else
1040 				gc[numctrl][1] = 0;
1041 		}
1042 	}
1043 	else
1044 		gc[numctrl][1] = 0;
1045 }
1046 
Command_Setcontrol_f(void)1047 void Command_Setcontrol_f(void)
1048 {
1049 	INT32 na;
1050 
1051 	na = (INT32)COM_Argc();
1052 
1053 	if (na != 3 && na != 4)
1054 	{
1055 		CONS_Printf(M_GetText("setcontrol <controlname> <keyname> [<2nd keyname>]: set controls for player 1\n"));
1056 		return;
1057 	}
1058 
1059 	setcontrol(gamecontrol);
1060 }
1061 
Command_Setcontrol2_f(void)1062 void Command_Setcontrol2_f(void)
1063 {
1064 	INT32 na;
1065 
1066 	na = (INT32)COM_Argc();
1067 
1068 	if (na != 3 && na != 4)
1069 	{
1070 		CONS_Printf(M_GetText("setcontrol2 <controlname> <keyname> [<2nd keyname>]: set controls for player 2\n"));
1071 		return;
1072 	}
1073 
1074 	setcontrol(gamecontrolbis);
1075 }
1076