1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: r:/prj/cit/src/RCS/movekeys.c $
21  * $Revision: 1.25 $
22  * $Author: mahk $
23  * $Date: 1994/11/22 22:53:07 $
24  *
25  */
26 
27 #include <stdlib.h>
28 
29 #include "input.h"
30 #include "player.h"
31 #include "physics.h"
32 #include "gamesys.h"
33 #include "weapons.h"
34 #include "movekeys.h"
35 
36 #define KEYBD_CONTROL_BANK 1
37 
38 // filled in MacSrc/Prefs.c
39 MOVE_KEYBIND MoveKeybinds[MAX_MOVE_KEYBINDS + 1];
40 MOVE_KEYBIND MoveCyberKeybinds[MAX_MOVE_KEYBINDS + 1];
41 
42 static uchar motion_key_scancodes[256 + 1];
43 static byte poll_controls[6];
44 
45 extern bool gKeypadOverride;
46 
47 uchar parse_motion_key(ushort code, short *cnum, short *cval);
48 uchar parse_motion_key_cyber(ushort code, short *cnum, short *cval);
49 void init_motion_polling(void);
50 void setup_motion_polling(void);
51 void process_motion_keys(void);
52 uchar motion_keycheck_handler(uiEvent *ev, LGRegion *, intptr_t);
53 
54 extern void physics_set_relax(int axis, uchar relax);
55 
parse_motion_key(ushort code,short * cnum,short * cval)56 uchar parse_motion_key(ushort code, short *cnum, short *cval) {
57     int i = 0, move = -1;
58 
59     *cnum = -1;
60     *cval = 0;
61 
62     while (MoveKeybinds[i].code != 255) {
63         if (code == MoveKeybinds[i].code) {
64             move = MoveKeybinds[i].move;
65             break;
66         }
67         i++;
68     }
69 
70     switch (move) {
71     case M_RUNFORWARD:
72         *cnum = CONTROL_YVEL;
73         *cval = CONTROL_MAX_VAL;
74         break;
75 
76     case M_FORWARD:
77         *cnum = CONTROL_YVEL;
78         *cval = CONTROL_MAX_VAL / 2;
79         break;
80 
81     case M_FASTTURNLEFT:
82         *cnum = CONTROL_XYROT;
83         *cval = -CONTROL_MAX_VAL;
84         break;
85 
86     case M_TURNLEFT:
87         *cnum = CONTROL_XYROT;
88         *cval = -CONTROL_MAX_VAL / 2;
89         break;
90 
91     case M_FASTTURNRIGHT:
92         *cnum = CONTROL_XYROT;
93         *cval = CONTROL_MAX_VAL;
94         break;
95 
96     case M_TURNRIGHT:
97         *cnum = CONTROL_XYROT;
98         *cval = CONTROL_MAX_VAL / 2;
99         break;
100 
101     case M_BACK:
102         *cnum = CONTROL_YVEL;
103         *cval = -CONTROL_MAX_VAL / 2;
104         break;
105 
106     case M_SLIDELEFT:
107         *cnum = CONTROL_XVEL;
108         *cval = -CONTROL_MAX_VAL / 2;
109         break;
110 
111     case M_SLIDERIGHT:
112         *cnum = CONTROL_XVEL;
113         *cval = CONTROL_MAX_VAL / 2;
114         break;
115 
116     case M_JUMP:
117         *cnum = CONTROL_ZVEL;
118         *cval = MAX_JUMP_CONTROL;
119         break;
120 
121     case M_LEANUP:
122         *cnum = CONTROL_XZROT;
123         *cval = 0;
124         physics_set_relax(*cnum, TRUE);
125         break;
126 
127     case M_LEANLEFT:
128         *cnum = CONTROL_XZROT;
129         *cval = -CONTROL_MAX_VAL;
130         physics_set_relax(*cnum, TRUE);
131         break;
132 
133     case M_LEANRIGHT:
134         *cnum = CONTROL_XZROT;
135         *cval = CONTROL_MAX_VAL;
136         physics_set_relax(*cnum, TRUE);
137         break;
138 
139     case M_LOOKUP:
140         *cnum = CONTROL_YZROT;
141         *cval = CONTROL_MAX_VAL;
142         break;
143 
144     case M_LOOKDOWN:
145         *cnum = CONTROL_YZROT;
146         *cval = -CONTROL_MAX_VAL;
147         break;
148 
149     case M_RUNLEFT:
150         *cnum = CONTROL_YVEL;
151         *cval = CONTROL_MAX_VAL;
152         if (abs(poll_controls[*cnum]) < abs(*cval))
153             poll_controls[*cnum] = *cval;
154         *cnum = CONTROL_XYROT;
155         *cval = -CONTROL_MAX_VAL / 2;
156         break;
157 
158     case M_RUNRIGHT:
159         *cnum = CONTROL_YVEL;
160         *cval = CONTROL_MAX_VAL;
161         if (abs(poll_controls[*cnum]) < abs(*cval))
162             poll_controls[*cnum] = *cval;
163         *cnum = CONTROL_XYROT;
164         *cval = CONTROL_MAX_VAL / 2;
165         break;
166     default:
167         // Unhandled movement. What I gonna do?
168         ;
169     }
170 
171     return *cnum != -1;
172 }
173 
parse_motion_key_cyber(ushort code,short * cnum,short * cval)174 uchar parse_motion_key_cyber(ushort code, short *cnum, short *cval) {
175     int i = 0, move = -1;
176 
177     code &= ~KB_FLAG_2ND;
178 
179     *cnum = -1;
180     *cval = 0;
181 
182     while (MoveCyberKeybinds[i].code != 255) {
183         if (code == MoveCyberKeybinds[i].code) {
184             move = MoveCyberKeybinds[i].move;
185             break;
186         }
187         i++;
188     }
189 
190     switch (move) {
191     case M_THRUST:
192         *cnum = CONTROL_ZVEL;
193         *cval = MAX_JUMP_CONTROL;
194         break;
195 
196     case M_CLIMB:
197         *cnum = CONTROL_YVEL;
198         *cval = -CONTROL_MAX_VAL;
199         break;
200 
201     case M_BANKLEFT:
202         *cnum = CONTROL_XYROT;
203         *cval = -CONTROL_MAX_VAL;
204         break;
205 
206     case M_BANKRIGHT:
207         *cnum = CONTROL_XYROT;
208         *cval = CONTROL_MAX_VAL;
209         break;
210 
211     case M_DIVE:
212         *cnum = CONTROL_YVEL;
213         *cval = CONTROL_MAX_VAL;
214         break;
215 
216     case M_ROLLRIGHT:
217         *cnum = CONTROL_XVEL;
218         *cval = -CONTROL_MAX_VAL;
219         break;
220 
221     case M_ROLLLEFT:
222         *cnum = CONTROL_XVEL;
223         *cval = CONTROL_MAX_VAL;
224         break;
225 
226     case M_CLIMBLEFT:
227         *cnum = CONTROL_YVEL;
228         *cval = -CONTROL_MAX_VAL;
229         if (abs(poll_controls[*cnum]) < abs(*cval))
230             poll_controls[*cnum] = *cval;
231         *cnum = CONTROL_XYROT;
232         *cval = -CONTROL_MAX_VAL;
233         break;
234 
235     case M_CLIMBRIGHT:
236         *cnum = CONTROL_YVEL;
237         *cval = -CONTROL_MAX_VAL;
238         if (abs(poll_controls[*cnum]) < abs(*cval))
239             poll_controls[*cnum] = *cval;
240         *cnum = CONTROL_XYROT;
241         *cval = CONTROL_MAX_VAL;
242         break;
243 
244     case M_DIVERIGHT:
245         *cnum = CONTROL_YVEL;
246         *cval = CONTROL_MAX_VAL;
247         if (abs(poll_controls[*cnum]) < abs(*cval))
248             poll_controls[*cnum] = *cval;
249         *cnum = CONTROL_XYROT;
250         *cval = CONTROL_MAX_VAL;
251         break;
252 
253     case M_DIVELEFT:
254         *cnum = CONTROL_YVEL;
255         *cval = CONTROL_MAX_VAL;
256         if (abs(poll_controls[*cnum]) < abs(*cval))
257             poll_controls[*cnum] = *cval;
258         *cnum = CONTROL_XYROT;
259         *cval = -CONTROL_MAX_VAL;
260         break;
261     default:
262         // Unhandled movement. What I gonna do?
263         ;
264     }
265 
266     return *cnum != -1;
267 }
268 
269 // always poll these codes; see init_motion_polling() below
270 static int always_motion_poll[] = {
271     CODE_UP,       // up arrow
272     CODE_DOWN,     // down arrow
273     CODE_LEFT,     // left arrow
274     CODE_RIGHT,    // right arrow
275     CODE_KP_HOME,  // keypad home
276     CODE_KP_UP,    // keypad up
277     CODE_KP_PGUP,  // keypad pgup
278     CODE_KP_LEFT,  // keypad left
279     CODE_KP_5,     // keypad 5
280     CODE_KP_RIGHT, // keypad right
281     CODE_KP_END,   // keypad end
282     CODE_KP_DOWN,  // keypad down
283     CODE_KP_PGDN,  // keypad pgdn
284     CODE_KP_ENTER, // keypad enter
285     CODE_ENTER,    // enter
286 
287     255            // signal end of list
288 };
289 
init_motion_polling(void)290 void init_motion_polling(void) {
291     int i, j = 0, code;
292     uchar used[256];
293 
294     // keep track of which codes have already been added
295     memset(used, 0, 256);
296 
297     // add move keybinds to list of scancodes to poll
298     i = 0;
299     while (MoveKeybinds[i].code != 255) {
300         code = MoveKeybinds[i].code & 255;
301         if (!used[code]) {
302             used[code] = 1;
303             motion_key_scancodes[j++] = code;
304         }
305         i++;
306     }
307 
308     // add move cyber keybinds to list of scancodes to poll
309     i = 0;
310     while (MoveCyberKeybinds[i].code != 255) {
311         code = MoveCyberKeybinds[i].code & 255;
312         if (!used[code]) {
313             used[code] = 1;
314             motion_key_scancodes[j++] = code;
315         }
316         i++;
317     }
318 
319     // always poll these codes, so add them if they weren't added already
320     i = 0;
321     while (always_motion_poll[i] != 255) {
322         code = always_motion_poll[i];
323         if (!used[code]) {
324             used[code] = 1;
325             motion_key_scancodes[j++] = code;
326         }
327         i++;
328     }
329 
330     motion_key_scancodes[j] = KBC_NONE; // signal end of list
331 
332     uiSetKeyboardPolling(motion_key_scancodes);
333 }
334 
setup_motion_polling(void)335 void setup_motion_polling(void) { LG_memset(poll_controls, 0, sizeof(poll_controls)); }
336 
process_motion_keys(void)337 void process_motion_keys(void) {
338     physics_set_player_controls(
339         KEYBD_CONTROL_BANK,
340         poll_controls[CONTROL_XVEL],
341         poll_controls[CONTROL_YVEL],
342         poll_controls[CONTROL_ZVEL],
343         poll_controls[CONTROL_XYROT],
344         poll_controls[CONTROL_YZROT],
345         poll_controls[CONTROL_XZROT]
346         );
347 }
348 
motion_keycheck_handler(uiEvent * ev,LGRegion * r,intptr_t data)349 uchar motion_keycheck_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
350     // KLC - For Mac version, we'll cook our own, since we have the modifier information.
351     ushort cooked = ev->poll_key_data.scancode | ev->poll_key_data.mods;
352 
353     short cnum, cval;
354     int moveOK = TRUE;
355 
356     if (gKeypadOverride) // if a keypad is showing
357     {
358         if (ev->poll_key_data.scancode >= 0x52 && ev->poll_key_data.scancode <= 0x5C) // and a keypad number was entered,
359             moveOK = FALSE;                               // don't move.
360     }
361 
362     if (moveOK) {
363         if ((global_fullmap->cyber && parse_motion_key_cyber(cooked, &cnum, &cval)) ||
364             parse_motion_key(cooked, &cnum, &cval)) {
365             if (abs(poll_controls[cnum]) < abs(cval))
366                 poll_controls[cnum] = cval;
367         }
368     }
369 
370     return TRUE;
371 }
372