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